코알못

[kubernetes] Secret으로 민감 데이터 관리 본문

ETC

[kubernetes] Secret으로 민감 데이터 관리

코린이s 2023. 6. 4. 23:55
728x90

설정 파일에는 비밀번호 같은 민감 정보가 있을 수 있다.

이런 민감 데이터를 관리하기 위한 오브젝트인 Secret을 사용하면 Base64로 인코딩하여 저장하고 불러올때는 디코딩해준다!

이번 실습은 nginx 인증서와 키 파일을 secret을 통해 저장하고 파드 볼륨에서 해당 secret에 있는 데이터를 불러오도록 하여 안전하게 관리 하도록 해보자!

인증서는 cert 디렉토리에 생성하도록 한다.

$ mkdir cert

nginx에 사용할 인증서와 키파일을 생성한다.

# 키 생성 
$ openssl genrsa -aes256 -out ./cert/corin.com.key 2048

# 개인키 자체 암호화 제거
$ cp ./corin.com.key ./cert/corin.com.key.enc
$ openssl rsa -in  ./cert/corin.com.key.enc -out ./cert/corin.com.key

# 개인키 group other 권한 제거 
$ chmod 600 ./cert/corin.com.key*

# csr 생성 (Common Name에 도메인 입력)
$ openssl req -new -key ./cert/corin.com.key -out ./cert/corin.com.csr

# 확인
$ openssl req -text -in ./cert/corin.com.csr

# csr > crt`
$ openssl x509 -req -days 365 -in ./cert/corin.com.csr -signkey ./cert/corin.com.key  -out ./cert/corin.com.crt

# 확인
$ openssl x509 -in ./cert/corin.com.crt -noout -text

이제 생성한 인증서를 저장할 secret을 생성하도록 한다.

$ kubectl create secret generic tls-config --from-file=cert
secret/tls-config created

secret의 데이터를 확인해보면 실제 데이터와 다른값이 저장 되어 있는데 이는 Base64로 인코딩 된 값임을 알 수 있다.

$ kubectl get secret tls-config -o yaml
apiVersion: v1
data:
  corin.com.crt: LS0tLS...
  corin.com.key: LS0tLS1CRU
kind: Secret
metadata:
  creationTimestamp: "2023-06-04T13:17:36Z"
  name: tls-config
  namespace: default
  resourceVersion: "22093594"
  uid: fb03a2b6-0cfe-4cf6-8f6c-bffa0a127084
type: Opaque

이는 아래와 같이 Base64로 디코딩 하면 실제 저장한 값이 나오며 이를 통해 Base64로 인코딩 된 값임을 알 수 있다.

$ kubectl get secret tls-config -o jsonpath='{.data.corin\.com\.crt}' | base64 --decode
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----

 

 

이제 인증서 관련 설정을 아래와 같이 진행한다.

ssl_certificate 부분의 인증서와 key 파일은 secret 을 통해 읽어올 예정이며 이는 뒤에서 yaml 파일에서 정의하도록 한다.

# server.conf

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    server_name corin.com;

    ssl_certificate tls/corin.com.crt; # 인증서 위치 (상대 경로이기에 /etc/nginx/tls/ 에서 읽음)
    ssl_certificate_key tls/corin.com.key; # 키 위치
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    access_log /var/log/nginx/host.access.log main;

    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
    }
    
    location /myapp {
        proxy_pass http://my-app:8080/;
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

이제 해당 server.conf 파일을 읽을  수 있도록 configmap 을 생성한다.

$ kubectl create configmap nginx-config --from-file=conf
configmap/nginx-config created
$ kubectl get configmap nginx-config -o yaml

이제 파드,  서비스를 생성하며 nginx 컨테이너에서 생성한 configmap, secret 을 읽을 수 있도록 volumes, volumeMounts를 정의한다.

secret 의 경우 secret.secretName 으로 secret을 파드 볼륨에서 읽어 올 수 있다. 사용은 컨테이너에서 볼륨 마운트 하면 된다. 

# web-server.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  selector:
    app: my-app
  ports:
  - port: 8080
    targetPort: 8080
---
apiVersion: v1
kind: Pod
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  containers:
    - name: my-app
      image: yoonjeong/my-app:1.0
      ports:
      - containerPort: 8080
      resources:
        limits:
          memory: "64Mi"
          cpu: "50m"
---
apiVersion: v1
kind: Pod
metadata:
  name: web-server
  labels:
    name: nginx
spec:
  volumes:
  - name: tls-config
    secret:
      secretName: tls-config
  - name: app-config
    configMap:
      name: nginx-config
  containers: 
    - name: nginx
      image: nginx
      ports:
      - containerPort: 80
      volumeMounts:
      - name: app-config
        mountPath: /etc/nginx/conf.d
      - name: tls-config
        mountPath: /etc/nginx/tls
      resources:
          limits:
            memory: "64Mi"
            cpu: "50m"
    - name: my-app
      image: yoonjeong/my-app:1.0
      ports:
      - containerPort: 8080
      resources:
        limits:
          memory: "64Mi"
          cpu: "50m"

클러스터에 적용한다.

$ kubectl apply -f web-server.yaml
service/my-app created
pod/my-app created
pod/web-server created

파드가 정상적으로 생성 되었다.

$ kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
my-app       1/1     Running   0          116s
web-server   2/2     Running   0          115s

이제 테스트를 위해 위에 생성한 도메인명으로 host 설정을 로컬에 한다.

$ sudo vi /etc/hosts
127.0.0.1       localhost corin.com

이제 cacert 옵션을 통해 클라이언트가 인증서를 신뢰할 수 있도록 하여 생성한 도메인의 myapp URL로 호출 하면 http status code 200을 받으며 정상적으로 통신 된다.

$ curl --cacert cert/corin.com.crt -sv https://corin.com:8443/myapp
*   Trying ::1...
* TCP_NODELAY set
* Connected to corin.com (::1) port 8443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: cert/corin.com.crt
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (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 change cipher, Change cipher spec (1):
* 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=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=corin.com
*  start date: Jun  4 13:03:18 2023 GMT
*  expire date: Jun  3 13:03:18 2024 GMT
*  common name: corin.com (matched)
*  issuer: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=corin.com
*  SSL certificate verify ok.
> GET /myapp HTTP/1.1
> Host: corin.com:8443
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.25.0
< Date: Sun, 04 Jun 2023 14:21:10 GMT
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Powered-By: Express
<
Welcome to Version 1!

===== Host Info =====
HostIP: 10.100.3.101
* Connection #0 to host corin.com left intact
HostName: my-app* Closing connection 0

실제 컨테이너의 인증서 확인시 정상적으로 디코딩 되어 저장 되어 있음을 알 수 있다.

$ kubectl exec web-server -c nginx -- cat /etc/nginx/tls/corin.com.crt
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

끝!

728x90
Comments