flavono123

Self-signed Certificate(NGINX)

Sat Feb 5, 2022

0. 준비

  • openssl3
  • kubernetes(minikube)

1. CA RSA 키 페어 생성

실제 CA가 아니라 우리가 직접 CA를 만들어 TLS 인증하는 과정을 모의로 해본다(self-signed certificate)

$ openssl genrsa -aes256 -out rootCA.key 2048
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:


$ ll rootCA.key 
-rw-------  1 hansuk  staff  1874 Jan 14 14:30 rootCA.key
  • 비밀키 분실을 대비하여 AES256으로 암호화 한다. 이때 passphrase를 잘 기억하고 발급할 때 사용하자

2. CA 인증서 발급

$ openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.crt
Enter pass phrase for rootCA.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:KR
State or Province Name (full name) [Some-State]:RootState
Locality Name (eg, city) []:RootCity
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Root Inc.
Organizational Unit Name (eg, section) []:Root CA
Common Name (e.g. server FQDN or YOUR name) []:Self-signed Root CA
Email Address []:

$ ll
total 16
-rw-r--r--  1 hansuk  staff  1033 Jan 14 14:45 rootCA.crt
-rw-------  1 hansuk  staff  1874 Jan 14 14:30 rootCA.key

상호작용하는 입력은 대충 해주어도 된다. 키 외에 crt 파일이 생긴걸 확인.

3. localhost(subject) CSR 생성

$ cat << EOF > localhost.csr.cnf
> [req]
> default_bits = 2048
> prompt = no
> default_md = sha256
> distinguished_name = dn
> 
> [dn]
> C=KR
> ST=Seoul
> L=Seocho-gu
> O=Localhost
> CN = localhost
> EOF

$ openssl req -new -sha256 -nodes -out localhost.csr -newkey rsa:2048 -keyout localhost.key -config localhost.csr.cnf
...+......+.....+...+.+.........+............+...+..+......+.......+...+...+..+....+.....+.............+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*............+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+..+.+...+......+.....+....+.....+...............+....+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.+............+..+......+.+...+........+...+....+......+..+...+.........+..................+....+...+...+..+...+...+....+......+............+..+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+.+...........+.......+.....+...+....+...+......+..+...+......+......+..................+.+......+.....+....+...+...+.........+....................+.+..+...+...+.......+...+............+..+...............+.+.........+...+........+.+.....+....+............+...+...........+...+......+....+........+...+......+.+...+.........+........+....+...+......+..+.............+......+........+.+..+...+......+...+..........+..+.............+......+.........+......+..+...+.+..............+.........+......+.+.....+...+...+.......+...+.....+..........+...+.........+...+..............+...+................+..+.........+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----

$ ll localhost.*
-rw-r--r--  1 hansuk  staff   985 Jan 14 14:53 localhost.csr
-rw-r--r--  1 hansuk  staff   141 Jan 14 14:52 localhost.csr.cnf
-rw-------  1 hansuk  staff  1704 Jan 14 14:53 localhost.key

위에서 CA CSR 발급 시 상호작용으로 입력했던 common name과 같은 입력 값을 파일에 쓰고 인자로 준다.

4. localhost 인증서 생성

$ cat << EOF > v3.ext 
> authorityKeyIdentifier=keyid,issuer
> basicConstraints=CA:FALSE
> keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
> subjectAltName = @alt_names
> 
> [alt_names]
> DNS.1 = localhost
> EOF

$ openssl x509 -req -in localhost.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out localhost.pem -days 365 -sha256 -extfile v3.ext 
Enter pass phrase for rootCA.key:

$ openssl verify -CAfile rootCA.crt localhost.pem 
localhost.pem: OK

X509 v3 확장 명세를 정의하고 인증서를 발급한다. alt_names (Subject Alternative Name, SAN)필드에 DNS.n를 추가하면 인증서로 신뢰할 수 있는 도메인을 추가할 수 있다.

5. subject 서버 준비

로컬 nginx에 인증서를 설치하여 인증을 테스트해본다. 먼저 인증서를 설치를 위한 시크릿과 설정맵도 만든다. 쿠버네티스는 TLS 타입에 대해 빌트인 시크릿이 정의되어 있다:

$ kubectl create secret tls nginxsecret --key localhost.key --cert localhost.pem
secret/nginxsecret created

$ cat << EOF > default.conf
> server {
>         listen 80 default_server;
>         listen [::]:80 default_server ipv6only=on;
> 
>         listen 443 ssl;
> 
>         root /usr/share/nginx/html;
>         index index.html;
> 
>         server_name localhost;
>         ssl_certificate /etc/nginx/ssl/tls.crt;
>         ssl_certificate_key /etc/nginx/ssl/tls.key;
> 
>         location / {
>                 try_files $uri $uri/ =404;
>         }
> }
> EOF

$ kubectl create configmap nginxconfmap --from-file=default.conf
configmap/nginxconfmap created

만든 인증서를 설치할 nginx 컨테이너를 up 한다:

apiVersion: v1
kind: Service
metadata:
  name: nginx-cert
  labels:
    app: nginx-cert
spec:
  type: NodePort
  ports:
  - port: 80
    protocol: TCP
    name: http
    nodePort: 30080
  - port: 443
    protocol: TCP
    name: https
    nodePort: 30443
  selector:
    app: nginx-cert
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: nginx-cert
  name: nginx-cert
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-cert
  template:
    metadata:
      labels:
        app: nginx-cert
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      - name: configmap-volume
        configMap:
          name: nginxconfmap
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
        - containerPort: 443
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume
        - mountPath: /etc/nginx/conf.d
          name: configmap-volume

6. SSL 요청

minikube 서비스 IP를 알아내어 openssl로 먼저 요청해본다:

$ minikube service --url nginx-cert -n cert
http://192.168.64.2:30080
http://192.168.64.2:30443


$ openssl s_client -CAfile rootCA.crt -connect 192.168.64.2:30443 2>/dev/null < /dev/null
CONNECTED(00000003)
---
Certificate chain
 0 s:C = KR, ST = Seoul, L = Seocho-gu, O = Localhost, CN = localhost
   i:C = KR, ST = RootState, L = RootCity, O = Root Inc., OU = Root CA, CN = Self-signed Root CA
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Jan 17 03:37:15 2022 GMT; NotAfter: Jan 17 03:37:15 2023 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDzzCCAregAwIBAgIUYMe6nRgsZwq9UPMKFgj9dt9z9FIwDQYJKoZIhvcNAQEL
BQAweDELMAkGA1UEBhMCS1IxEjAQBgNVBAgMCVJvb3RTdGF0ZTERMA8GA1UEBwwI
Um9vdENpdHkxEjAQBgNVBAoMCVJvb3QgSW5jLjEQMA4GA1UECwwHUm9vdCBDQTEc
MBoGA1UEAwwTU2VsZi1zaWduZWQgUm9vdCBDQTAeFw0yMjAxMTcwMzM3MTVaFw0y
MzAxMTcwMzM3MTVaMFkxCzAJBgNVBAYTAktSMQ4wDAYDVQQIDAVTZW91bDESMBAG
A1UEBwwJU2VvY2hvLWd1MRIwEAYDVQQKDAlMb2NhbGhvc3QxEjAQBgNVBAMMCWxv
Y2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALc9retjBorw
RKbuyC1SNx1U9L5LJPPbBkBh4kg98saQxtRX0Wqs5mgswWMZYL3E6yRl0gfwBkdq
t8GVQ49dgg0QO5MbG9ylfCLS9xR3WWjAgxaDJ0W96PyvTzmg295aqqHFKPSaG/nM
JyZgFJDuGoRRgwoWNqZ1pRCDLMIENDx4qgjOnQch529pM9ZRwFQSswKpn4BVkY00
/u8jIvax67kFOg70QGY16paGEg7YfSNle7BFZY0VJ8rIiBoqwRmPH6hbF/djxe5b
yzkI9eqts9bqw8eDLC28S36x62FxkdqkK8pI/rzWAKSV43TWML1zq4vM2bI+vp0k
a06GhSsS1bUCAwEAAaNwMG4wHwYDVR0jBBgwFoAUURHNpOE9zTgXgVYAGvLt94Ym
P+8wCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwFAYDVR0RBA0wC4IJbG9jYWxob3N0
MB0GA1UdDgQWBBSS1ZHHT6OHTomYIRsmhz6hMJLGnDANBgkqhkiG9w0BAQsFAAOC
AQEAWA23pCdAXtAbdSRy/p8XURCjUDdhkp3MYA+1gIDeGAQBKNipU/KEo5wO+aVk
AG6FryPZLOiwiP8nYAebUxOAqKG3fNbgT9t95BEGCip7Cxjp96KNYt73Kl/OTPjJ
KZUkHQ7MXN4vc5gmca8q+OqwCCQ/daMkzLabPQWNk3R/Hzo/mT42v8ht9/nVh1Ml
u3Dow5QPp8LESrJABLIRyRs0+Tfp+WodgekgDX5hnkkSk77+oXB49r2tZUeG/CVv
Fg8PuUNi+DWpdxX8fE/gIbSzSsamOf29+0sCIoJEPvk7lEVLt9ca0SoJ7rKn/ai4
HxwTiYo9pNcoLwhH3xdXjvbuGA==
-----END CERTIFICATE-----
subject=C = KR, ST = Seoul, L = Seocho-gu, O = Localhost, CN = localhost
issuer=C = KR, ST = RootState, L = RootCity, O = Root Inc., OU = Root CA, CN = Self-signed Root CA
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1620 bytes and written 390 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: 00C994177DCF3DA424433CD0EDB33FF54C1198D0DE2C08D61BBD155D85890F20
    Session-ID-ctx: 
    Master-Key: B88A94A3556F9A595B3B395E0F4701290D3837BC49CA125CA25E0351261E7C59F0DF0928B4A12E33509B38B2F2684711
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - 5d 96 c8 cf 8f 9c 9f c4-15 25 b9 57 56 13 ec 9d   ]........%.WV...
    0010 - 2a 26 f8 e5 09 e4 01 11-fa 59 25 a1 6c e7 ba 94   *&.......Y%.l...
    0020 - 85 b2 6c 49 b1 1f 78 6c-4c b1 ed b1 af 1b ce 46   ..lI..xlL......F
    0030 - c6 f1 bd f8 36 da b0 c4-31 ce ba 62 72 4b 76 a1   ....6...1..brKv.
    0040 - 2d d4 b6 8d cb c3 39 ee-8f 05 77 48 9e 61 3e 4a   -.....9...wH.a>J
    0050 - 2c 6b f4 19 59 f4 93 cf-bd d7 16 76 ce af 48 b5   ,k..Y......v..H.
    0060 - b7 cc c2 aa 9b 36 44 b5-93 4e 1e 8a 96 6c e7 96   .....6D..N...l..
    0070 - b5 0e 04 96 77 d7 df 2a-ef 70 ad c1 7b 82 a9 3a   ....w..*.p..{..:
    0080 - 5c 9b 4a 94 fb ea dc de-15 11 fa 3b e1 af dd cf   \.J........;....
    0090 - 57 48 98 ed c8 d7 6b 5d-00 c3 84 5f 86 0c a8 b5   WH....k]..._....
    00a0 - 18 66 52 14 c4 9c b0 ff-0b 39 12 b6 0a 78 49 4d   .fR......9...xIM

    Start Time: 1644478485
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: yes
---

브라우저에서도 확인해본다. openssl 요청 시 CAfile 옵션으로 CA 인증서를 넘겨 주었지만, 브라우저 요청에 적용하기 위해선 맥 시스템 키체인에 추가해야한다. 신뢰 탭을 펼쳐 이 인증서 사용 시 항상 신뢰로 변경하자: 1

2

참고

comments powered by Disqus