DEV Community

Cover image for Little step to use PKI easiest
Watcharin(start)
Watcharin(start)

Posted on • Edited on

Little step to use PKI easiest

From previous posts, I said about What is PKI. Then this post, I will explain How to use them in some case and next post I will give an advanced technique for PKI.

This lab will simulate the scenario in how we can use PKI to make secure communication. All this session we work on terminal, you can following in step-by-step.

Prerequisite

  • CLI terminal(On linux or something like that)
  • OpenSSL
  • cURL
  • Docker
  • tree

Use self-sign to secure communication

Scenario: We will provide simple web server and map SSL certificate on it. We create connection with cURL and debug it to see what's happen in handshake state. Then, we compare between insecure and secure.

  1. Generate SSL with CN is ssl-lab.example.local.
    $ openssl req -newkey rsa:4096 -nodes -keyout ssl/ssl-lab.example.local.key \
        -x509 -sha256 -days 3 \
        -subj "/C=TH/ST=BKK/O=Opsta/OU=DevOps/CN=ssl-lab.example.local" \
        -addext "subjectAltName = DNS:ssl-lab.example.local, DNS:localhost, DNS:127.0.0.1" \
        -out ssl/ssl-lab.example.local.crt

    Generating a RSA private key
    ...................++++
    ..............................................................................++++
    writing new private key to 'ssl-lab.example.local.key'
    -----
Enter fullscreen mode Exit fullscreen mode

Explain command.

For create certificated, we use OpenSSL library to create and manage them.

You can use following arguments to generate 2 files like private and public key:

req = request new resources

-newkey rsa:4096 = create new private key with length 4096 keys.

-nodes = export output key with plaintext.

-keyout /path/to/save/file.key = specific location to save private key.

-x509 = output with x509 structure.

-sha256 = choose a message digest algorithm.

-days 3 = expired date for this certificate in 3 day.

-subj "something" = quick add metadata for certificate. The arg must be formatted as /type0=value0/type1=value1/type2=..., characters may be escaped by \ (backslash), no spaces are skipped.

-addext "something" = add some extension metadata. The arg must be formatted as key=value

-out = specific location to save public key and digital certificate.

Check file should created.

    $ tree ssl

    ssl
    ├── ssl-lab.example.local.crt
    └── ssl-lab.example.local.key
    0 directories, 2 files
Enter fullscreen mode Exit fullscreen mode
  1. Verify certificate is matched with openssl cli.

    $ openssl x509 -noout -modulus -in ssl/ssl-lab.example.local.crt | openssl md5
    (stdin)= ac9173e222ab6b766e49da3069268dd0
    # OUTPUT will difference in your terminal
    
    $ openssl rsa -noout -modulus -in ssl/ssl-lab.example.local.key | openssl md5
    (stdin)= ac9173e222ab6b766e49da3069268dd0
    

    If your see same stdin in 2 output, you're right.

  2. Now, you already to create web server in docker for learn how SSL work. First, you will check your docker daemon working and run a sample Nginx web server.

    Create a Nginx site config in following.

    <!-- file location in ./config/default.conf -->
    server {
        listen       80;
        server_name  localhost ssl-lab.example.local;
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
    server {
        listen              443 ssl;
        server_name         localhost ssl-lab.example.local;
        keepalive_timeout   70;
        ssl_certificate     /etc/nginx/ssl/ssl-lab.example.local.crt;
        ssl_certificate_key /etc/nginx/ssl/ssl-lab.example.local.key;
        ssl_protocols       TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers off;
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
    

    Create a Dockerfile in following.

    FROM nginx:1.20-alpine
    
    ADD config/default.conf /etc/nginx/conf.d/default.conf
    
    COPY ssl /etc/nginx/ssl
    
    RUN chown -R 0:0 /etc/nginx/ssl \
        && chown -R 0:0 /etc/nginx/conf.d/default.conf
    

    Then, build customize http server in docker.

    $ docker build -t http:lab .
    
    Sending build context to Docker daemon  233.5kB
    Step 1/4 : FROM nginx:1.20-alpine
     ---> 5c05ca045835
    Step 2/4 : ADD config/default.conf /etc/nginx/conf.d/default.conf
     ---> Using cache
     ---> 1284fcf47f5b
    Step 3/4 : COPY ssl /etc/nginx/ssl
     ---> 920c31460cbf
    Step 4/4 : RUN chown -R 0:0 /etc/nginx/ssl     && chown -R 0:0 /etc/nginx/conf.d/default.conf
     ---> Running in f8bfa038944f
    Removing intermediate container f8bfa038944f
     ---> 725ee42e058b
    Successfully built 725ee42e058b
    Successfully tagged http:lab
    
  3. You can run http(s) server in terminal.

    docker run -it --rm -p 8080:80 -p 8443:443 http:lab
    
  4. Verify http server has running with docker ps or curl http://localhost:8080. It just return result on STDOUT.

    $ docker ps
    
    CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                                                                            NAMES
    1235d24fe059   http:lab   "/docker-entrypoint.…"   7 minutes ago   Up 7 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp, 0.0.0.0:8443->443/tcp, :::8443->443/tcp   relaxed_montalcini
    
  5. You can use cURL to see what happen.

    Get web page with insecure protocol(HTTP).

    $ curl -v http://localhost:8080
    
    *   Trying 127.0.0.1:8080...
    * Connected to localhost (127.0.0.1) port 8080 (#0)
    > GET / HTTP/1.1
    > Host: localhost:8080
    > User-Agent: curl/7.74.0
    > Accept: */*
    > 
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < Server: nginx/1.20.2
    < Date: Mon, 18 Apr 2022 11:45:35 GMT
    < Content-Type: text/html
    < Content-Length: 612
    < Last-Modified: Tue, 16 Nov 2021 15:04:23 GMT
    < Connection: keep-alive
    < ETag: "6193c877-264"
    < Accept-Ranges: bytes
    < 
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    * Connection #0 to host localhost left intact
    

    Use curl in default option and see error in https tunnel.

    $ curl -v https://localhost:8443
    
    *   Trying 127.0.0.1:8443...
    * Connected to localhost (127.0.0.1) port 8443 (#0)
    * ALPN, offering h2
    * ALPN, offering http/1.1
    * successfully set certificate verify locations:
    *  CAfile: /etc/ssl/certs/ca-certificates.crt
    *  CApath: /etc/ssl/certs
    * TLSv1.3 (OUT), TLS handshake, Client hello (1):
    * TLSv1.3 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (OUT), TLS alert, unknown CA (560):
    * SSL certificate problem: self signed certificate
    * Closing connection 0
    curl: (60) SSL certificate problem: self signed certificate
    More details here: https://curl.se/docs/sslcerts.html
    
    curl failed to verify the legitimacy of the server and therefore could not
    establish a secure connection to it. To learn more about this situation and
    how to fix it, please visit the web page mentioned above.
    

    In the error response, We can translate in a part of message.

    1. They're try to make a connection to endpoint.

      Trying 127.0.0.1:8443...  
      Connected to localhost (127.0.0.1) port 8443 (#0)
      
    2. They're prepared information for connection.

      ALPN, offering h2  
      ALPN, offering http/1.1  
      successfully set certificate verify locations:  
        CAfile: /etc/ssl/certs/ca-certificates.crt  
        CApath: /etc/ssl/certs 
      
    3. They're send first contact message in hello.

      TLSv1.3 (OUT), TLS handshake, Client hello (1):  
      TLSv1.3 (IN), TLS handshake, Server hello (2):
      
    4. Server send digital certificate to client.

       TLSv1.2 (IN), TLS handshake, Certificate (11):
      
    5. Client verify certificate integrity and found in self-sign issue.

      TLSv1.2 (OUT), TLS alert, unknown CA (560):
      SSL certificate problem: self signed certificate
      
    6. Client close connection and report error message.

      Closing connection 0  
      curl: (60) SSL certificate problem: self signed certificate  
      More details here: 'https://curl.se/docs/sslcerts.html'  
      
      curl failed to verify the legitimacy of the server and therefore could not  
      establish a secure connection to it. To learn more about this situation and  
      how to fix it, please visit the web page mentioned above.  
      
  6. You can use crt certificate file in previous step to trust this communication.

    You can see normal establish connection in debug log.

    $ curl -v --cacert ssl/ssl-lab.example.local.crt https://localhost:8443
    
    *   Trying 127.0.0.1:8443...
    * Connected to localhost (127.0.0.1) port 8443 (#0)
    * ALPN, offering h2
    * ALPN, offering http/1.1
    * successfully set certificate verify locations:
    *  CAfile: ssl/ssl-lab.example.local.crt
    *  CApath: /etc/ssl/certs
    * TLSv1.3 (OUT), TLS handshake, Client hello (1):
    * TLSv1.3 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
    * ALPN, server accepted to use http/1.1
    * Server certificate:
    *  subject: C=TH; ST=BKK; O=Opsta; OU=DevOps; CN=ssl-lab.example.local
    *  start date: Apr 17 15:41:24 2022 GMT
    *  expire date: Apr 20 15:41:24 2022 GMT
    *  subjectAltName: host "localhost" matched cert\'s "localhost"
    *  issuer: C=TH; ST=BKK; O=Opsta; OU=DevOps; CN=ssl-lab.example.local
    *  SSL certificate verify ok.
    > GET / HTTP/1.1
    > Host: localhost:8443
    > User-Agent: curl/7.74.0
    > Accept: */*
    > 
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < Server: nginx/1.20.2
    < Date: Mon, 18 Apr 2022 12:03:50 GMT
    < Content-Type: text/html
    < Content-Length: 612
    < Last-Modified: Tue, 16 Nov 2021 15:04:23 GMT
    < Connection: keep-alive
    < ETag: "6193c877-264"
    < Accept-Ranges: bytes
    

Conclusion

You can see how to use PKI concept to make secure communication in this post. Then, you can adapt this step to your application to basic secure communication.

See ya in next posts to use CA for intermediate issuer.

Top comments (0)