PKI를 가장 쉽게 사용하기 위한 작은 단계

이전 게시물에서 What is PKI에 대해 말했습니다. 그럼 이번 포스트에서 설명하고How to use them in some case 다음 포스트에서는 PKI에 대한 고급 기술을 알려드리겠습니다.

이 실습에서는 PKI를 사용하여 보안 통신을 만드는 방법에 대한 시나리오를 시뮬레이션합니다. 터미널에서 작업하는 이 모든 세션은 단계별로 따라할 수 있습니다.

전제 조건


  • CLI 터미널(Linux 등에서)
  • OpenSSL
  • 도커
  • 나무

  • 통신 보안을 위해 자체 서명 사용



    시나리오: 간단한 웹 서버를 제공하고 SSL 인증서를 매핑합니다. cURL과의 연결을 생성하고 디버깅하여 핸드셰이크 상태에서 어떤 일이 발생하는지 확인합니다. 그런 다음 안전하지 않은 것과 안전한 것을 비교합니다.
  • CN을 사용하여 SSL 생성은 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'
        -----
    


    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.



    확인 파일이 생성되어야 합니다.

        $ tree ssl
    
        ssl
        ├── ssl-lab.example.local.crt
        └── ssl-lab.example.local.key
        0 directories, 2 files
    



  • 인증서가 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.



  • 이제 SSL 작동 방식을 배우기 위해 이미 도커에 웹 서버를 만들었습니다. 먼저 docker 데몬이 작동하는지 확인하고 샘플 Nginx 웹 서버를 실행합니다.

    다음에서 Nginx 사이트 구성을 만듭니다.

    <!-- 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;
        }
    }
    

    다음에서 Dockerfile을 만듭니다.

    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
    

    그런 다음 docker에서 사용자 지정 http 서버를 빌드합니다.

    $ 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
    


  • 터미널에서 http(s) 서버를 실행할 수 있습니다.

    docker run -it --rm -p 8080:80 -p 8443:443 http:lab
    


  • http 서버가 docker ps 또는 curl http://localhost:8080로 실행 중인지 확인합니다. 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
    

  • cURL를 사용하여 무슨 일이 일어나는지 확인할 수 있습니다.

    안전하지 않은 프로토콜(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
    

    기본 옵션에서 curl를 사용하고 https 터널에서 오류를 확인하십시오.

    $ 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.
    

    오류 응답에서 메시지의 일부를 번역할 수 있습니다.

  • 끝점에 연결하려고 합니다.

    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 
    


  • 그들은 hello에서 첫 번째 연락처 메시지를 보냅니다.

    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.  
    




  • 이전 단계에서 crt 인증서 파일을 사용하여 이 통신을 신뢰할 수 있습니다.

    디버그 로그에서 정상적인 연결 설정을 볼 수 있습니다.

    $ 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
    



  • 결론



    이 게시물에서 PKI 개념을 사용하여 보안 통신을 만드는 방법을 확인할 수 있습니다. 그런 다음 기본 보안 통신에 대한 애플리케이션에 이 단계를 적용할 수 있습니다.
    CA를 중간 발급자로 사용하려면 다음 게시물에서 뵙겠습니다.

    좋은 웹페이지 즐겨찾기