CakeDC Blog

TIPS, INSIGHTS AND THE LATEST FROM THE EXPERTS BEHIND CAKEPHP

TLS/ SSL Certificates Explained – Why your website should have one

SSL certificates are incredibly important if you want a safe and secure site - especially for end user reassurance. But what are they and why should you be concerned if you do not have one for your website?

Confidential information can be exposed to prying eyes, hackers or cyber criminals - SSL certificates offer a line of defense against this.

SSL - secure sockets layer) certificates are small data files that are digitally bind a cryptographic key to an organization’s details. When installed on a web server, it activates the padlock and the https protocol. This allows for secure connections between a web server to the browser. They were created to protect sensitive data in transmission. It is designed to provide security while remaining simple enough for everyday use.

Typically, these certificates are used to secure credit card transactions, data transfers and logins.

The SSL protocol has been traditionally used to encrypt and secure transmitted data. Each time a new and more secure version was released, only the version number changed to reflect the update. However, when the update from SSLv3.0 to the new version was released, the version was renamed to TLSv1.0.

Because SSL is still the recognised name, this is what most people refer to when describing these certificates - however, you are actually likely using/getting a TLS certificate. This is important to remember if you get a third party to purchase your certificate and you would like to make sure you are getting the right version/protocol.

When secured by TLS, connections have one or more of the following properties:

  • The connection is private/secure because symmetric cryptography is used to encrypt the data transmitted.

  • The identity of the communicating parties can be authenticated using public-key cryptography.

  • The connection ensures integrity because each message transmitted includes a message integrity check using a message authentication code to prevent undetected loss or alteration of the data during transmission.

What is important to also know is that browsers are going to start penalising HTTP sites from 2017. Why? Well because browsers, like Google, want to make it known to their users of sites that may be less secure or do not have a SSL certificate and are collecting sensitive information. From January 2017, Google has started flagging HTTP pages that collect passwords or credit card details as non secure. Ideally, website owners should get onto this as soon as possible and ensure that their sites are secured.

Visitors have also started to expect secure sites, research has indicated that they are specifically looking out for a ‘padlock’ or secure notification. This is important to sites in general - not only websites with an online store or login portal. SSL is more than just encrypting data submissions.

Have you heard about letsencrypt.org? Let’s Encrypt is a free, automated, and open certificate authority (CA), run for the public’s benefit. It is a service provided by the Internet Security Research Group (ISRG). Letsencrypt.org makes certificates more accessible while guiding you with how to properly set it up.

 

Latest articles

How to push Docker image to Container Registry and create App on...

The title speaks for itself, let’s jump right in! As a preliminary step, we start from a user registered in DigitalOcean with a validated account. Use the doctl tool for the entire communication process with DigitalOcean.

Step 1: Install doctl

$ cd ~
$ wget https://github.com/digitalocean/doctl/releases/download/v1.71.0/doctl-1.71.0-linux-amd64.tar.gz
$ tar xvf doctl-1.71.0-linux-amd64.tar.gz
$ sudo mv doctl /usr/local/bin
 

Step 2: Create an API token

  Go to https://cloud.digitalocean.com/account/api/tokens Generate new token for read and write and save apart the value of token generated <TOKEN NAME>: personaltoken 
<TOKEN VALUE>: 6e981fc2a674dbb7a610b9b85d0c8b00

Step 3: Use the API token to grant account access to doctl

$ doctl auth init --context personaltoken
Validating token... OK
Prompt for <TOKEN VALUE>, then enter it and press return 
 

Step 4: Validate that doctl is working

$ doctl auth init  Validating token... OK
  Prompt for <TOKEN VALUE>, then enter it and press return  Validate by obtaining the account information
$ doctl account get Email      Droplet Limit    Email Verified    UUID         Status email@cakedc.com    10     true     5415bbf8-d501-4096-9b75-ab781c017948    active
 

Step 5: Create a Container Registry with doctl

<MY-REGISTRY-NAME> : container-nyc-795 <REGION> : nyc3
$ doctl registry create container-nyc-795 --region nyc3 Name       Endpoint        Region slug container-nyc-795    registry.digitalocean.com/container-nyc-795    nyc3

Important: the region of the Container registry and Kubernetes cluster MUST be the same Keep in mind that container names must be unique, must be lowercase, and only accepts alphanumeric characters and hyphens.  

Step 6: Login to authenticate docker with your registry

$ doctl registry login
Logging Docker in to registry.digitalocean.com
 

Step 7: Create kubernetes cluster

$ doctl kubernetes cluster create cluster-static-example --region nyc3 Notice: Cluster is provisioning, waiting for cluster to be running ................................................................... Notice: Cluster created, fetching credentials Notice: Adding cluster credentials to kubeconfig file found in "/home/andres/.kube/config" Notice: Setting current-context to do-nyc3-cluster-static-example ID                                      Name                      Region    Version        Auto Upgrade    Status     Node Pools d24f180b-6007-4dbc-a2fe-3952801570aa    cluster-static-example    nyc3      1.22.7-do.0    false           running    cluster-static-example-default-pool
Important: the region of the Container registry and Kubernetes cluster MUST be the same here as well.  This operation isn’t a fast process.  

Step 8: Integrate kubernetes cluster in Container register

$ doctl kubernetes cluster registry add cluster-static-example
 

Step 9: Get token certificate and connect to cluster

$ doctl kubernetes cluster kubeconfig save cluster-static-example Notice: Adding cluster credentials to kubeconfig file found in "/home/andres/.kube/config" Notice: Setting current-context to do-nyc3-cluster-static-example
To validate this, use the kubectl tool to get context. If is not installed, get the last version you find - for example in googleapis
$ wget https://storage.googleapis.com/kubernetes-release/release/v1.23.5/bin/linux/amd64/kubectl
$ chmod +x kubectl
$ sudo mv kubectl /usr/local/bin/
Check with
$ kubectl config current-context
do-nyc3-cluster-static-example
Here, you see: bash prompt do-ny3-cluster-sttic-example. That is the context you created in Step 7
 

Step 10: Generate docker image, tag and push to DigitalOcean

We assume that the user already has docker installed
$ mkdir myapp
$ mkdir myapp/html
$ nano myapp/Dockerfile
  Inside Dockerfile put   
FROM nginx:latest
COPY ./html/hello.html /usr/share/nginx/html/hello.htm
l
  We create simple Dockerfile with NGINX Server and copy the file hello.html in the default html of nginx  
$ nano myapp/html/hello.html
  Inside hello.html put  
<!DOCTYPE html> <html>  <head>    <title>Hello World!</title>  </head>  <body>    <p>This is an example of a simple HTML page served from the Nginx container.</p>  </body> </html>
Then build a docker image file tag with repository and push with docker
 
$ cd myapp
$ docker build -t registry.digitalocean.com/container-nyc-795/static-app .
Sending build context to Docker daemon  3.584kB Step 1/2 : FROM nginx:latest latest: Pulling from library/nginx c229119241af: Pull complete 2215908dc0a2: Pull complete 08c3cb2073f1: Pull complete 18f38162c0ce: Pull complete 10e2168f148a: Pull complete c4ffe9532b5f: Pull complete Digest: sha256:2275af0f20d71b293916f1958f8497f987b8d8fd8113df54635f2a5915002bf1 Status: Downloaded newer image for nginx:latest  ---> 12766a6745ee Step 2/2 : COPY ./html/hello.html /usr/share/nginx/html/hello.html  ---> 2b9be913c377 Successfully built 2b9be913c377 Successfully tagged registry.digitalocean.com/container-nyc-795/static-app:latest   $ docker images REPOSITORY                                               TAG       IMAGE ID       CREATED         SIZE registry.digitalocean.com/container-nyc-795/static-app   latest    2b9be913c377   2 minutes ago   142MB   $ docker push registry.digitalocean.com/container-nyc-795/static-app Using default tag: latest The push refers to repository [registry.digitalocean.com/container-nyc-795/static-app] ac03ae036a53: Pushed ea4bc0cd4a93: Pushed fac199a5a1a5: Pushed 5c77d760e1f4: Pushed 33cf1b723f65: Pushed ea207a4854e7: Pushed 608f3a074261: Pushed latest: digest: sha256:22615ad4c324ca5dc13fe2c3e1d2d801bd166165e3809f96ed6a96a2b2ca2748 size: 1777


Step 11: Create app

Create file example-static-app.yaml and insert: alerts:                                 
- rule: DEPLOYMENT_FAILED               
- rule: DOMAIN_FAILED                   
name: example-static-app                
region: nyc                             
services:                               
- http_port: 80                         
  image:                                
    registry_type: DOCR                 
    repository: static-app              
    tag: latest                         
  instance_count: 2                     
  instance_size_slug: professional-xs   
  name: static-service                  
  routes:                               
  - path: /                             
  source_dir: /             
              Validate file with
$  doctl apps spec validate example-static-app.yaml
Create app
$ doctl apps create --spec example-static-app.yaml
Notice: App created
ID        Spec Name             Default Ingress    Active Deployment ID    In Progress Deployment ID    Created At     Updated At
55a7cb68-65b7-4ff1-b6af-388cdb1df507    example-static-app   2022-03-30 09:34:01.288257225 +0000 UTC    2022-03-30 09:34:01.288257225 +0000 UTC
If you access https://cloud.digitalocean.com/apps And in the live url + /hello.html you can see:

Step 12: Deploy app

If you modify the code of your app, you need to generate a new image with docker and push  (see step 10). Then you don’t need to create a new app, you need to deploy the image in the already created app, with the id executing the command to deploy in bash.
$  doctl apps create-deployment 55a7cb68-65b7-4ff1-b6af-388cdb1df507

 

How to generate deploy of Docker image to Container Registry on DigitalOcean Platform Apps

Once you have created the application (and if you have the code in gitlab), you can create a direct deployment of your code in the DigitalOcean container and deploy on top of your application.

Step 1: Define variables

First two variables are defined in gitlab. You can find these inside project in the left menu - enter in Settings > CI/CD > Variables $DIGITALOCEAN_API_KEY = token generated in DigitalOcean dashboard $APP_ID = previously generated application identifier   More can be defined as the name of the repository. The value of these variables will be injected into the file that we will create below in the Step 3  

 

Step 2: Register runner in gitlab

In your project in the left menu, go to Settings > CI/CD > Runners Create a specific runner for the project in the URL with registration token. Register GitLab Runner from the command line. It is important to use docker and privileged
# Download the binary for your system
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64

# Give it permission to execute
sudo chmod +x /usr/local/bin/gitlab-runner

# Register runner
sudo gitlab-runner register -n --url https://git.cakedc.com --registration-token GR1348941gx7sgV3pZFQgRqg5qUR_ --executor docker --description "My Docker Runner" --docker-image "docker:19.03.12" --docker-privileged --docker-volumes "/certs/client"
 

Step 3: Create file gitlab-ci.yml 

The gitlab-ci.yml file takes care of

  • Authentication and identification using doctl in DigitalOcean
  • Generating and sending the docker image to the DigitalOcean container
  • Deploying the container image to an existing app
Create the file gitlab-ci.yml in the root of your project as
image: docker:20-dind

variables:
  DOCKER_HOST: tcp://docker:2375
  DOCKER_DRIVER: overlay2
  DOCKER_TLS_CERTDIR: ""
  REPOSITORY_URL: registry.digitalocean.com/container-nyc-795/static-app
  CONTAINER_NAME: static-app

services:
  - name: docker:20-dind
    alias: docker
    command: ["--tls=false"]

before_script:
  - apk update
  - apk upgrade
  - apk add doctl --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community
  - docker info

build:
  stage: build
  script:
    - doctl auth init --access-token $DIGITALOCEAN_API_KEY
    - doctl account get     
    - echo $DIGITALOCEAN_API_KEY | docker login -u $DIGITALOCEAN_API_KEY --password-stdin registry.digitalocean.com
    - docker build -t $REPOSITORY_URL:latest .
    - docker push $REPOSITORY_URL
    - doctl apps create-deployment $APP_ID
Now, every time you do a git push in your project, the runner will automatically inject the variables defined previously in the gitlab-ci.yml file. Then, it will generate a docker image with docker (docker-in-docker) to create an image of your project, send it to the digitalocean repository and deploy it in the app configured.   That’s it!  

CakeFest 2021 Recap

Here we are again coming off of the CakeFest sugar high! I don’t even know where to begin.    Unfortunately, or fortunately - I haven’t decided, we had to do another virtual event. The safety of speakers, staff and attendees is very important to us, so a physical event was not the best option in our opinion with traveling.    However, after this event, I started thinking about the people who were able to attend from the comfort of their own homes or offices. These people may not have been able to travel or attend otherwise, and that gives me our silver lining. Not to mention that we had more ticket sales this year than any of our previous events (at least that I can remember).    The theme, for me anyway, ha ha, was traveling the world, ironically. We started in the Canary Islands, traveled to Germany, to Canada, to England and Austria. We had new faces from the US, the Czech Republic and even Japan - and more! This is, as I’ve mentioned, one of the best things about the CakePHP community, we have community members all over the world. This was our chance to come together.    So let’s get to the event. Here’s what you may have missed: 

Workshops:

Workshop 1 Jorge González (Twitter: @steinkelz) Topics covered included: 0:00 - Docker development environment for CakePHP 15:56 - Middlewares  30:05 - Security 1:31:36 - Performance optimization 2:04:49 - Events   Workshop 2 Michael Hoffmann (Twitter: @cleptric) Topics covered included: 0:00:00 -Setup login action in CakePHP 0:29:10 - Vite with hot reloading Vue.js tailwind css   Workshop 3 Mark Story (Twitter: @mark_story) Topics covered included: 0:04:25 - Leveraging new style fixtures 0:48:26 - Using the DI container 1:30:13 - Browser automation testing with Panther. 2:17:13 - Helpers you may need.
 

Talks:

* Juan Pablo Ramirez (Twitter: @jpramidev) gave the keynote talk on behalf of Passbolt. * Sho Ito (Twitter: @itosho) taught us all about Components * Yuki Kanazawa (Twitter: @yakitori009) and this talk about Automatically Distributing Reference Queries to    Read Replica in CakePHP4 * Mark Scherer (Twitter: @dereuromark) schooled attendees on IDE in CakePHP development * Jiri Havlicek (Twitter: @Jerryhavl) played a big role in fighting COVID-19 by helping create a  contact tracing app (developed with CakePHP) in Czech Republic * Chris Miller (Twitter: @ccmiller2019) explained standards and why we use them * Kevin Phifer (Twitter: @lordsimal)  joined in to explain how to re-use code - utility classes and PHP namespaces * Paul Henriks created a plugin with attendees LIVE * Ed Barnard (Twitter: @ewbarnard) brought the dragons! He talked about finding the Joy in Software Development * Chris Hartjes (Twitter: @grmpyprogrammer) delivered a Grumpy Programmer's Guide to being a senior developer  * Joe Ferguson (Twitter: @joepferguson) shared his knowledge on Modern Infrastructure as code with Ansible * Timo Stark (Twitter: @linux_lenny) shared details about NGINX Unit - and how to modernize your CakePHP deployments

Trivia and giveaways 

Cake ceremony dedicated to Mark Story

We took this time to thank and acknowledge Mark Story for all of his hard work and dedication that he puts into CakePHP. He then headed the cake cutting ceremony (virtually of course) as speakers and attendees enjoyed their own treats!   See the full archive here: https://cakefest.org/archive/virtual-2021  

So what’s to come? 

First!  Videos are starting to be released. With the help of community member Aroop Roelofs, we will be releasing these videos faster than expected. Ticket holders have been receiving access, and they will be released publicly in the coming days.  In regards to future events, it’s up in the air. We will have some internal discussions about safety measures and restrictions, then we will weigh the option between another virtual or physical event. We will, of course, reach out to the community for their input.  I will close by just saying THANK YOU. Thank you for making my job worth it. When an event runs smoothly and gets so much great feedback, that is a direct reflection from the community support. We hope you all will continue to join us in years to come!    Thanks for baking!  

Dependency Injection with CakePHP

Let’s talk about Dependency Injection!

SOLID principles

As you know SOLID is an acronym for the  five object-oriented design principles. In this topic, we will focus on Interface segregation principle and Dependency inversion principle. Interface segregation principle states that a client must not be forced to implement an interface that they do not use, or clients shouldn’t be forced to depend on methods they do not use. In other words, having  many client-specific interfaces is better than one general-purpose interface. From the other side, Dependency inversion principle states that objects must depend on abstractions, not on concretions. It states that the high-level module must not depend on the low-level module, but they should depend on abstractions. To follow Dependency inversion principle, we need to construct low-level modules and pass them to constructors, and that might create a lot of manual work for developers. The dependency injection container is created specifically for solving the problem with manual construction of an object, before creating a specific object. If we follow interface segregation principle when developing application modules, it would be easy to configure a container and switch module dependency. This is where the interface shows its incredible power.  

Few words about CakePHP Events System

CakePHP Events System was created to allow injecting some logic using listeners. However, in some cases, it is used to get results from code that will be created by the module user. When an event is dispatched by the listener, it can return the result. Callback injection through the event system has some drawbacks. First of all, parameters passed to the event need to pass as a hash array. So unfortunately, there is no way to check that all params are really passed or to be sure that all passed params have correct types. Is there a way to solve this problem? Yes, and containers could help with that. Instead of passing events, we can get the required object from the container and call it method. But you could say: wait, we don't know what object could be used in client code within the developed plugin. That's fine, and this  is where interface segregation principle can help. In our plugin, we define an interface for each such case, and instead of dispatching an event, we can easily get an object from the container by interface.       $updater = $container->get(AfterLoginInterface::class);     if ($updater !== null) {         $user = $updater->afterLogin($user);     }   In the Application::services method, users link the interface with the specific class.       public function services(ContainerInterface $container): void     {         $container->add(AfterLoginInterface::class, MyAfterLogin::class);     }   In some of default behavior needed we can map service class for container to default implementation using Plugin::services method.       public function services(ContainerInterface $container): void     {         if (!$container->has(AfterLoginInterface::class)) {             $container->add(AfterLoginInterface::class, NullAfterLogin::class);         }     }  

Container propagation

Dependency injection is an experimental feature. Initial implementation limited by Controllers constructors and methods, and Commands constructors. If we want to access the container in other parts of the application, we may want to propagate it from app level. The most logical way would be to implement middleware and store the container inside the request attribute.   <?php declare(strict_types=1);   namespace App\Middleware;   use Cake\Core\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use RuntimeException;   /**  * Container Injector Middleware  */ class ContainerInjectorMiddleware implements MiddlewareInterface {     /**      * @var \Cake\Core\ContainerInterface      */     protected $container;       /**      * Constructor      *      * @param \Cake\Core\ContainerInterface $container The container to build controllers with.      */     public function __construct(ContainerInterface $container)     {         $this->container = $container;     }       /**      * Serve assets if the path matches one.      *      * @param \Psr\Http\Message\ServerRequestInterface $request The request.      * @param \Psr\Http\Server\RequestHandlerInterface $handler The request handler.      * @return \Psr\Http\Message\ResponseInterface A response.      */     public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface     {         return $handler->handle($request->withAttribute('container', $this->container));     }   That’s it! I hope that this will help you when you are baking with dependency injections. If you run into any problems, there are many support channels that allow the CakePHP community to help  You can check them out under the community tab at CakePHP.org.

We Bake with CakePHP