[kubernetes] ConfigMap & Secret

728x90

ConfigMap & Secret

공식 문서: https://kubernetes.io/ko/docs/concepts/configuration/configmap/

컨피그맵은 키-값 쌍으로 기밀이 아닌 데이터를 저장하는 데 사용하는 API 오브젝트이다. 파드는 볼륨에서 환경 변수, 커맨드-라인 인수 또는 **구성 파일(key=파일명, value=내용)**로 컨피그맵을 사용할 수 있다.

주로 설정파일, 인증서, 암호화 키를 제공할 때 ConfigMap 과 Secret 을 사용한다.

컨피그맵을 사용하면 컨테이너 이미지에서 환경별 구성을 분리하여, 애플리케이션을 쉽게 이식할 수 있다.

예제

apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
data:
  # 속성과 비슷한 키; 각 키는 간단한 값으로 매핑됨
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # 파일과 비슷한 키
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5    
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true

환경 변수

my-config.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mymessage
data:
  MESSAGE: Customized Hello ConfigMap

mymessage 컨피그맵의 모든 키를 환경 변수로 등록한다.

myweb.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      envFrom:
        - configMapRef:
            name: mymessage

valueFrom 필드 사용, mymessage 컨피그맵의 특정 키를 뽑아서 환경 변수로 사용할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
	    env:  
				valueFrom:
					configMapKeyRef:
						key: MESSAGE
						name: mymessage
kubectl exec -it myweb-env -- sh
/ # env
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.233.0.1:443
HOSTNAME=myweb-env
SHLVL=1
HOME=/root
TERM=xterm
KUBERNETES_PORT_443_TCP_ADDR=10.233.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP=tcp://10.233.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
MESSAGE=Customized Hello ConfigMap
KUBERNETES_SERVICE_HOST=10.233.0.1
PWD=/

파일

myweb-cm-vol.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-cm-vol
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      volumeMounts:
        - name: cmvol
          mountPath: /myvol
  volumes:
    - name: cmvol
      configMap:
        name: mymessage

my-config.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mymessage
data:
  MESSAGE: Customized Hello ConfigMap

Secret

공식 문서: https://kubernetes.io/ko/docs/concepts/configuration/secret/

value 를 base64 로 인코딩하여 encoded data 를 만든다. 암호화라고 하지만 전혀 안전한 방식은 아니다.

그래서 AWS KMS, Hashicorp Vault 와 연동하여 암호화를 하여 안전하게 사용할 수 있다.

시크릿은 암호, 토큰 또는 키와 같은 소량의 중요한 데이터를 포함하는 오브젝트이다. 이를 사용하지 않으면 중요한 정보가 파드 spec 이나 컨테이너 이미지에 포함될 수 있다. 시크릿을 사용한다는 것은 사용자의 기밀 데이터를 애플리케이션 코드에 넣을 필요가 없음을 뜻한다.

시크릿은 시크릿을 사용하는 파드와 독립적으로 생성될 수 있기 때문에, 파드를 생성하고, 확인하고, 수정하는 워크플로우 동안 시크릿(그리고 데이터)이 노출되는 것에 대한 위험을 경감시킬 수 있다. 쿠버네티스 및 클러스터에서 실행되는 애플리케이션은 기밀 데이터를 비휘발성 저장소에 쓰는 것을 피하는 것과 같이, 시크릿에 대해 추가 예방 조치를 취할 수도 있다.

시크릿은 컨피그맵과 유사하지만 특별히 기밀 데이터를 보관하기 위한 것이다.

시크릿 타입

시크릿을 생성할 때, Secret 리소스의 type 필드를 사용하거나, (활용 가능하다면) kubectl 의 유사한 특정 커맨드라인 플래그를 사용하여 시크릿의 타입을 명시할 수 있다. 시크릿 타입은 여러 종류의 기밀 데이터를 프로그래밍 방식으로 용이하게 처리하기 위해 사용된다.

쿠버네티스는 일반적인 사용 시나리오를 위해 몇 가지 빌트인 타입을 제공한다. 이 타입은 쿠버네티스가 부과하여 수행되는 검증 및 제약에 따라 달라진다.

Opaque, service-account-token, dockercfg, dockerconfigjson, tls 정도가 중요하다.

mydata.yml

apiVersion: v1
kind: Secret
metadata:
  name: mydata
type: Opaque
data:
  id: YWRtaW4K
  pwd: MTIzNAo=

myweb.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      envFrom:
        - configMapRef:
            name: mymessage

mydata 시크릿의 모든 키를 환경 변수로 등록한다.

myweb.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      envFrom:
        - secretRef:
            name: mymessage

valueFrom 필드 사용, mydata 시크릿의 특정 키를 뽑아서 환경 변수로 사용할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
	    env:  
				valueFrom:
					secretKeyRef:
						key: id
						name: mydata

myweb-cm-vol.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-secret-vol
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      volumeMounts:
        - name: secret-vol
          mountPath: /myvol
  volumes:
    - name: secret-vol
      secret:
        name: mydata

Nginx POD 에 HTTPs 적용

Nginx

  • documentation root: /usr/share/nginx/html
  • Configuration File: /etc/nginx/conf.d

자체 서명 인증서 생성

Secret 리소스로 생성

  • Type:

Private key

openssl genrsa -out nginx-tls.key 2048

Public Key

openssl rsa -in nginx-tls.key -pubout -out nginx-tls

CSR

openssl req -new -key nginx-tls.key -out nginx-tls.csr

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]:Seoul
Locality Name (eg, city) []:Seoul
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Dev
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:www.example.com
Email Address []:admin@test.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

CRT(인증서)

원래라면 csr(certificate sign request) 파일을 CA 에 업로드해서 제 3자 인증을 받고 .crt 파일을 가져오면 되지만, 간단하게 자체 서명 인증을 통해 .crt 파일을 만든다.

openssl req -x509 -days 3650 -key nginx-tls.key -in nginx-tls.csr -out nginx-tls.crt

설정 파일

nginx-tls.conf

server {
    listen              80;
    listen              443 ssl;
    server_name         myapp.example.com;
    ssl_certificate     /etc/nginx/ssl/tls.crt;
    ssl_certificate_key /etc/nginx/ssl/tls.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    location / {
        root   /usr/share/nginx/html;
        index  index.html;
    }
}

Secret

base64 x509/nginx-tls.crt -w 0
base64 x509/nginx-tls.key -w 0
apiVersion: v1
kind: Secret
metadata:
	name: nginx-secret
type: kubernetes.io/tls
data:
	tls.crt: |
		LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ1VENDQXMyZ0F3SUJBZ0lVQ2NFOTM4WEZFSnBLYjU2NTlJZERTUFBJYmQwd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZRXhDekFKQmdOVkJBWVRBa3RTTVE0d0RBWURWUVFJREFWVFpXOTFiREVPTUF3R0ExVUVCd3dGVTJWdgpkV3d4RERBS0JnTlZCQW9NQTBSbGRqRUxNQWtHQTFVRUN3d0NTVlF4R0RBV0JnTlZCQU1NRDNkM2R5NWxlR0Z0CmNHeGxMbU52YlRFZE1Cc0dDU3FHU0liM0RRRUpBUllPWVdSdGFXNUFkR1Z6ZEM1amIyMHdIaGNOTWpJd05USTAKTURjeE5UTTJXaGNOTXpJd05USXhNRGN4TlRNMldqQ0JnVEVMTUFrR0ExVUVCaE1DUzFJeERqQU1CZ05WQkFnTQpCVk5sYjNWc01RNHdEQVlEVlFRSERBVlRaVzkxYkRFTU1Bb0dBMVVFQ2d3RFJHVjJNUXN3Q1FZRFZRUUxEQUpKClZERVlNQllHQTFVRUF3d1BkM2QzTG1WNFlXMXdiR1V1WTI5dE1SMHdHd1lKS29aSWh2Y05BUWtCRmc1aFpHMXAKYmtCMFpYTjBMbU52YlRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTnBQR3RRRwp2OCtPRmFYeW1rZlBrQVU3cHRodFBjWlZ4bGRYVVV0M2hYZUh5NWRBWjhNSDhFaVRNZXdDRmlmYUNqZHpqcVVmCjZzd1JjVkxBQzJWYkt5bk56Z0U1cVJYMXRhazJDd2Uwb1hRcUFBSE1rY3FJSlJIaTRKRThZVlJZU3p3dUpxZmUKOUZ5N2h5Ri9ZY0xZR05DVmpkYVpKOXR6SnZ3UW85S2VKaEFlcnVNZzZSRmE5UnFEUGxRNFBFbnNaNVRKTllxNApRbmRKRzJQZW8xMHYrUVF6TmUxYmZqOG1CMnFtc0ZmMktIeXdPb3dxNytLMEpKUjl4MlY3ZUtUTzVxU2N6RWdrCk9DQ3VhbFFRcmVBa2xvVUZSZGFYazJuWXFYcUhna3c0UkZIc3JHS3RYQlhsd2ppSVZsWXdMUURKTGxpTFdTNVAKTUx5bis5TEpRQzU0ZHA4Q0F3RUFBYU5UTUZFd0hRWURWUjBPQkJZRUZHZnk1VDZuSDRPYjVDRksrQWd0bktTMwpzNjVaTUI4R0ExVWRJd1FZTUJhQUZHZnk1VDZuSDRPYjVDRksrQWd0bktTM3M2NVpNQThHQTFVZEV3RUIvd1FGCk1BTUJBZjh3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUZ0dlhBL1VCN3MvSDhGZHMyZXYxMjZlMU02aEtxTmoKRDhLV0dFMm1taW9hbjF0MVhPZGx1bDc1LzZEa0pkTGxNQVJWaGhUYzhHaVZDK2dqMXF5MVBlekpqQk5ZZDJXMApxVVVOcXYxczd4VmtKdEhpMSs1dlBDNy9OMXBhYXVPVDJXTFdNWlhMVVR4QWxLZmRwRWxHVWFYUzdsK0tLOUxmCjBEVEdxWFROemRsNE8xM2hFU1dkZ1dIQ1ptY0RSc2g5MTUxSG5JaU5vaHRuN1laY2FCL1RSbnJlbDJhRVRkeUYKS3ZablVRZTIvRHdGVzVNcVBMejQvdHYxbVlpWlZoMVN3bjl2ZHV5RG9qSTZUNUhnK0xHblBVOEhUZkg3eVBDUgp4cWRDMkovTnZFNWtOUEViTVF4MUlTMWhOR2o0TDJKVWNJNXEwNm1DM0VMUnpUSXBURi9mMTlRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
	tls.key: |
		LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBMms4YTFBYS96NDRWcGZLYVI4K1FCVHVtMkcwOXhsWEdWMWRSUzNlRmQ0ZkxsMEJuCnd3ZndTSk14N0FJV0o5b0tOM09PcFIvcXpCRnhVc0FMWlZzcktjM09BVG1wRmZXMXFUWUxCN1NoZENvQUFjeVIKeW9nbEVlTGdrVHhoVkZoTFBDNG1wOTcwWEx1SElYOWh3dGdZMEpXTjFwa24yM01tL0JDajBwNG1FQjZ1NHlEcApFVnIxR29NK1ZEZzhTZXhubE1rMWlyaENkMGtiWTk2alhTLzVCRE0xN1Z0K1B5WUhhcWF3Vi9Zb2ZMQTZqQ3J2CjRyUWtsSDNIWlh0NHBNN21wSnpNU0NRNElLNXFWQkN0NENTV2hRVkYxcGVUYWRpcGVvZUNURGhFVWV5c1lxMWMKRmVYQ09JaFdWakF0QU1rdVdJdFpMazh3dktmNzBzbEFMbmgybndJREFRQUJBb0lCQUdLUFhEbGxZcXUrSmgvcAp5NldvSEFtQXlPN2xRd0tNTHlPM2xFaFNDYnZSWHlWR09wSmV2eWpFNjhEMW9ETVZ5WThIYU5zNzhiRjRIb1dSCmxwT0grWkRDRGNPWDJMTEZYK0twTjRtZkQxVjJzTklmSGFNbW5EWGJEREFGNXB0QjBaVzE4RlhSM3RrUEFROHEKaDJTRVU0KzROWFV4YUVFM1Y5NXRWTWorQllrNHU0eDM0bnZ2enJwdGFISER3QmVUOGdqYU9XbXMrd2lQWk5uZgpzanJGRWJ4VTZGeFZSazlWSEF3SGlTZ2ZPbGdOeFlzU25zYU85ZGtrV05GU0I1Mi8vVXRKK0szRnZrV3JLUG1qCmJYN3FtSlNaeHJFN09SeXFhK3lqZkZBWmYrajkxalczL09MNkM2ajNPMFRXV05aTlA1RjRldHFYZVBiN1lIMmkKOUcwb01jRUNnWUVBOG5qc1dUZnVmUVZYQVBLWHZGOW1UQUtsU0lzL3Vua2t3RVloWFh1WGtFRU9wOExEaVN2WQpwSnFzT3NUSlRRaE5mM0g0dWg4Rkl5SHFSb3BlS3VYYy9jSmFsRTFUejREZUN0d2c5R0xjVHpuaGV1RVVsTWhnCnNycVFucjFDTDJtRHd1MTFLL0w0MURHTkNaWFEyYWNmT1pYcCtLdkEzV0ZheVRLNzRDbHNKY2tDZ1lFQTVuMFMKYVlvQy9saEhHeGRqeDdOQTZUNDJVV1grMTFaRTZSSGRKWWtTa3NQWXdhYzlYUnFLWHlzcytrUnY4U2tUaUZMOAp5dnlRcjFyaWlGRWp6VkN2YjA5WjllRWw3UngyT3F3eEpISEJ3bFdKWUEvRFdLN3ZkbHdvZ21wbUhCVzdaQ1k1ClBRVVJSOWhmbC9TVk1selVjSFpyK1J1QmhqWElhTFd2KzdBM2pTY0NnWUFJeHArblN3THl1M0src2drVDVGQUwKaUR6N055OERUTWNydmw0T3lCNWdOanFWajlNTDcrNVRadFc4K3NwZVkyS0tybEZXU3pFZ2FHWFdUOFBBd2JrUgo1aXJwR3pOaFcwU3VGL0dKWnRxYWMzblp2TFBGL3NxaExXZDJsMXNCNUV2RWpsdWpUNVA1K2lFa3E2dDNkVGtJCkdJanpXeVFMM3k0dUFnd1N2TzBSSVFLQmdCVlZha2plZjF4dmExVjBtc1czTDhEbkF6d1JocjhEdXlrZmdDcWoKUDFiYVRjdk80UDBuSWJ1aFVXNXd1elBGSzR1b3NzRlBFMDFIeWtQM3pxcUlWMVNrTVoxeWs0SVk2bENQODVSOQord016eTUxYW1DZ3pPUExwb001QmJ1WVdsTnUyTmdJUjRBR1lZM0M3TUx3U240OHhSdGt0MUpWSmtSMHdBL1AxCjRZNXRBb0dCQUpHTlJKK3plRmdnR25OK25NdjNVa0ZTVDYxMEp3bi9QeWdUYTZPK3FZMlp0dHFITTBYKzRGM04KalpiSGpmTHlZZS9JaWZNMVpKR1M1ZUxTc0xjOFBjM0NaRUF3S05VUDkvQ2xsTCthamhibmwrdHRJOVBBZTFGeQorU1JSSVlPV1pZakFMNC82ZkNjL0UxY3g1OW9UVzR4eHBFRUtEck5rckxIY09iUTcxVVNuCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
	name: nginx-conf
data:  

server-conf: |
server {
    listen              80;
    listen              443 ssl;
    server_name         myapp.example.com;
    ssl_certificate     /etc/nginx/ssl/tls.crt;
    ssl_certificate_key /etc/nginx/ssl/tls.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    location / {
        root   /usr/share/nginx/html;
        index  index.html;
    }
}

Pod 생성

apiVersion: v1
kind: Pod
metadata:
	name: nginx-https-pod
	labels:
		app: nginx
spec:
	containers:
		- name: nginx
			image: nginx
			volumeMounts:
				- name: confvol
					mountPath: /etc/nginx/conf.d
				- name: secvol
					mountPath: /etc/nginx/ssl
	volumes:
		- name: confvol
			configMap:
				name: nginx-conf
		- name: secvol
			secret:
				name: nginx-secret

Service

apiVersion:
kind: Service
metadata:
	name: nginx-svc
spec:
	type: LoadBalancer
	selector:
		app: nginx
	ports:
		- name: http
			port: 80
			targetPort:80
		- name: httpsp
			port: 443
			targetPort: 443

Test

curl --insecure

Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.

Thank you for using nginx.

ConfigMap & Secret

공식 문서: https://kubernetes.io/ko/docs/concepts/configuration/configmap/

컨피그맵은 키-값 쌍으로 기밀이 아닌 데이터를 저장하는 데 사용하는 API 오브젝트이다. 파드는 볼륨에서 환경 변수, 커맨드-라인 인수 또는 **구성 파일(key=파일명, value=내용)**로 컨피그맵을 사용할 수 있다.

주로 설정파일, 인증서, 암호화 키를 제공할 때 ConfigMap 과 Secret 을 사용한다.

컨피그맵을 사용하면 컨테이너 이미지에서 환경별 구성을 분리하여, 애플리케이션을 쉽게 이식할 수 있다.

예제

apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
data:
  # 속성과 비슷한 키; 각 키는 간단한 값으로 매핑됨
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # 파일과 비슷한 키
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5    
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true

환경 변수

my-config.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mymessage
data:
  MESSAGE: Customized Hello ConfigMap

mymessage 컨피그맵의 모든 키를 환경 변수로 등록한다.

myweb.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      envFrom:
        - configMapRef:
            name: mymessage

valueFrom 필드 사용, mymessage 컨피그맵의 특정 키를 뽑아서 환경 변수로 사용할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
	    env:  
				valueFrom:
					configMapKeyRef:
						key: MESSAGE
						name: mymessage
kubectl exec -it myweb-env -- sh
/ # env
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.233.0.1:443
HOSTNAME=myweb-env
SHLVL=1
HOME=/root
TERM=xterm
KUBERNETES_PORT_443_TCP_ADDR=10.233.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP=tcp://10.233.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
MESSAGE=Customized Hello ConfigMap
KUBERNETES_SERVICE_HOST=10.233.0.1
PWD=/

파일

myweb-cm-vol.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-cm-vol
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      volumeMounts:
        - name: cmvol
          mountPath: /myvol
  volumes:
    - name: cmvol
      configMap:
        name: mymessage

my-config.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mymessage
data:
  MESSAGE: Customized Hello ConfigMap

Secret

공식 문서: https://kubernetes.io/ko/docs/concepts/configuration/secret/

value 를 base64 로 인코딩하여 encoded data 를 만든다. 암호화라고 하지만 전혀 안전한 방식은 아니다.

그래서 AWS KMS, Hashicorp Vault 와 연동하여 암호화를 하여 안전하게 사용할 수 있다.

시크릿은 암호, 토큰 또는 키와 같은 소량의 중요한 데이터를 포함하는 오브젝트이다. 이를 사용하지 않으면 중요한 정보가 파드 spec 이나 컨테이너 이미지에 포함될 수 있다. 시크릿을 사용한다는 것은 사용자의 기밀 데이터를 애플리케이션 코드에 넣을 필요가 없음을 뜻한다.

시크릿은 시크릿을 사용하는 파드와 독립적으로 생성될 수 있기 때문에, 파드를 생성하고, 확인하고, 수정하는 워크플로우 동안 시크릿(그리고 데이터)이 노출되는 것에 대한 위험을 경감시킬 수 있다. 쿠버네티스 및 클러스터에서 실행되는 애플리케이션은 기밀 데이터를 비휘발성 저장소에 쓰는 것을 피하는 것과 같이, 시크릿에 대해 추가 예방 조치를 취할 수도 있다.

시크릿은 컨피그맵과 유사하지만 특별히 기밀 데이터를 보관하기 위한 것이다.

시크릿 타입

시크릿을 생성할 때, Secret 리소스의 type 필드를 사용하거나, (활용 가능하다면) kubectl 의 유사한 특정 커맨드라인 플래그를 사용하여 시크릿의 타입을 명시할 수 있다. 시크릿 타입은 여러 종류의 기밀 데이터를 프로그래밍 방식으로 용이하게 처리하기 위해 사용된다.

쿠버네티스는 일반적인 사용 시나리오를 위해 몇 가지 빌트인 타입을 제공한다. 이 타입은 쿠버네티스가 부과하여 수행되는 검증 및 제약에 따라 달라진다.

Opaque, service-account-token, dockercfg, dockerconfigjson, tls 정도가 중요하다.

mydata.yml

apiVersion: v1
kind: Secret
metadata:
  name: mydata
type: Opaque
data:
  id: YWRtaW4K
  pwd: MTIzNAo=

myweb.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      envFrom:
        - configMapRef:
            name: mymessage

mydata 시크릿의 모든 키를 환경 변수로 등록한다.

myweb.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      envFrom:
        - secretRef:
            name: mymessage

valueFrom 필드 사용, mydata 시크릿의 특정 키를 뽑아서 환경 변수로 사용할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: myweb-env
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
	    env:  
				valueFrom:
					secretKeyRef:
						key: id
						name: mydata

myweb-cm-vol.yml

apiVersion: v1
kind: Pod
metadata:
  name: myweb-secret-vol
spec:
  containers:
    - name: myweb
      image: ghcr.io/c1t1d0s7/go-myweb:alpine
      volumeMounts:
        - name: secret-vol
          mountPath: /myvol
  volumes:
    - name: secret-vol
      secret:
        name: mydata

Nginx POD 에 HTTPs 적용

Nginx

  • documentation root: /usr/share/nginx/html
  • Configuration File: /etc/nginx/conf.d

자체 서명 인증서 생성

Secret 리소스로 생성

  • Type:

Private key

openssl genrsa -out nginx-tls.key 2048

Public Key

openssl rsa -in nginx-tls.key -pubout -out nginx-tls

CSR

openssl req -new -key nginx-tls.key -out nginx-tls.csr

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]:Seoul
Locality Name (eg, city) []:Seoul
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Dev
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:www.example.com
Email Address []:admin@test.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

CRT(인증서)

원래라면 csr(certificate sign request) 파일을 CA 에 업로드해서 제 3자 인증을 받고 .crt 파일을 가져오면 되지만, 간단하게 자체 서명 인증을 통해 .crt 파일을 만든다.

openssl req -x509 -days 3650 -key nginx-tls.key -in nginx-tls.csr -out nginx-tls.crt

설정 파일

nginx-tls.conf

server {
    listen              80;
    listen              443 ssl;
    server_name         myapp.example.com;
    ssl_certificate     /etc/nginx/ssl/tls.crt;
    ssl_certificate_key /etc/nginx/ssl/tls.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    location / {
        root   /usr/share/nginx/html;
        index  index.html;
    }
}

Secret

base64 x509/nginx-tls.crt -w 0
base64 x509/nginx-tls.key -w 0
apiVersion: v1
kind: Secret
metadata:
	name: nginx-secret
type: kubernetes.io/tls
data:
	tls.crt: |
		LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ1VENDQXMyZ0F3SUJBZ0lVQ2NFOTM4WEZFSnBLYjU2NTlJZERTUFBJYmQwd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZRXhDekFKQmdOVkJBWVRBa3RTTVE0d0RBWURWUVFJREFWVFpXOTFiREVPTUF3R0ExVUVCd3dGVTJWdgpkV3d4RERBS0JnTlZCQW9NQTBSbGRqRUxNQWtHQTFVRUN3d0NTVlF4R0RBV0JnTlZCQU1NRDNkM2R5NWxlR0Z0CmNHeGxMbU52YlRFZE1Cc0dDU3FHU0liM0RRRUpBUllPWVdSdGFXNUFkR1Z6ZEM1amIyMHdIaGNOTWpJd05USTAKTURjeE5UTTJXaGNOTXpJd05USXhNRGN4TlRNMldqQ0JnVEVMTUFrR0ExVUVCaE1DUzFJeERqQU1CZ05WQkFnTQpCVk5sYjNWc01RNHdEQVlEVlFRSERBVlRaVzkxYkRFTU1Bb0dBMVVFQ2d3RFJHVjJNUXN3Q1FZRFZRUUxEQUpKClZERVlNQllHQTFVRUF3d1BkM2QzTG1WNFlXMXdiR1V1WTI5dE1SMHdHd1lKS29aSWh2Y05BUWtCRmc1aFpHMXAKYmtCMFpYTjBMbU52YlRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTnBQR3RRRwp2OCtPRmFYeW1rZlBrQVU3cHRodFBjWlZ4bGRYVVV0M2hYZUh5NWRBWjhNSDhFaVRNZXdDRmlmYUNqZHpqcVVmCjZzd1JjVkxBQzJWYkt5bk56Z0U1cVJYMXRhazJDd2Uwb1hRcUFBSE1rY3FJSlJIaTRKRThZVlJZU3p3dUpxZmUKOUZ5N2h5Ri9ZY0xZR05DVmpkYVpKOXR6SnZ3UW85S2VKaEFlcnVNZzZSRmE5UnFEUGxRNFBFbnNaNVRKTllxNApRbmRKRzJQZW8xMHYrUVF6TmUxYmZqOG1CMnFtc0ZmMktIeXdPb3dxNytLMEpKUjl4MlY3ZUtUTzVxU2N6RWdrCk9DQ3VhbFFRcmVBa2xvVUZSZGFYazJuWXFYcUhna3c0UkZIc3JHS3RYQlhsd2ppSVZsWXdMUURKTGxpTFdTNVAKTUx5bis5TEpRQzU0ZHA4Q0F3RUFBYU5UTUZFd0hRWURWUjBPQkJZRUZHZnk1VDZuSDRPYjVDRksrQWd0bktTMwpzNjVaTUI4R0ExVWRJd1FZTUJhQUZHZnk1VDZuSDRPYjVDRksrQWd0bktTM3M2NVpNQThHQTFVZEV3RUIvd1FGCk1BTUJBZjh3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUZ0dlhBL1VCN3MvSDhGZHMyZXYxMjZlMU02aEtxTmoKRDhLV0dFMm1taW9hbjF0MVhPZGx1bDc1LzZEa0pkTGxNQVJWaGhUYzhHaVZDK2dqMXF5MVBlekpqQk5ZZDJXMApxVVVOcXYxczd4VmtKdEhpMSs1dlBDNy9OMXBhYXVPVDJXTFdNWlhMVVR4QWxLZmRwRWxHVWFYUzdsK0tLOUxmCjBEVEdxWFROemRsNE8xM2hFU1dkZ1dIQ1ptY0RSc2g5MTUxSG5JaU5vaHRuN1laY2FCL1RSbnJlbDJhRVRkeUYKS3ZablVRZTIvRHdGVzVNcVBMejQvdHYxbVlpWlZoMVN3bjl2ZHV5RG9qSTZUNUhnK0xHblBVOEhUZkg3eVBDUgp4cWRDMkovTnZFNWtOUEViTVF4MUlTMWhOR2o0TDJKVWNJNXEwNm1DM0VMUnpUSXBURi9mMTlRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
	tls.key: |
		LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBMms4YTFBYS96NDRWcGZLYVI4K1FCVHVtMkcwOXhsWEdWMWRSUzNlRmQ0ZkxsMEJuCnd3ZndTSk14N0FJV0o5b0tOM09PcFIvcXpCRnhVc0FMWlZzcktjM09BVG1wRmZXMXFUWUxCN1NoZENvQUFjeVIKeW9nbEVlTGdrVHhoVkZoTFBDNG1wOTcwWEx1SElYOWh3dGdZMEpXTjFwa24yM01tL0JDajBwNG1FQjZ1NHlEcApFVnIxR29NK1ZEZzhTZXhubE1rMWlyaENkMGtiWTk2alhTLzVCRE0xN1Z0K1B5WUhhcWF3Vi9Zb2ZMQTZqQ3J2CjRyUWtsSDNIWlh0NHBNN21wSnpNU0NRNElLNXFWQkN0NENTV2hRVkYxcGVUYWRpcGVvZUNURGhFVWV5c1lxMWMKRmVYQ09JaFdWakF0QU1rdVdJdFpMazh3dktmNzBzbEFMbmgybndJREFRQUJBb0lCQUdLUFhEbGxZcXUrSmgvcAp5NldvSEFtQXlPN2xRd0tNTHlPM2xFaFNDYnZSWHlWR09wSmV2eWpFNjhEMW9ETVZ5WThIYU5zNzhiRjRIb1dSCmxwT0grWkRDRGNPWDJMTEZYK0twTjRtZkQxVjJzTklmSGFNbW5EWGJEREFGNXB0QjBaVzE4RlhSM3RrUEFROHEKaDJTRVU0KzROWFV4YUVFM1Y5NXRWTWorQllrNHU0eDM0bnZ2enJwdGFISER3QmVUOGdqYU9XbXMrd2lQWk5uZgpzanJGRWJ4VTZGeFZSazlWSEF3SGlTZ2ZPbGdOeFlzU25zYU85ZGtrV05GU0I1Mi8vVXRKK0szRnZrV3JLUG1qCmJYN3FtSlNaeHJFN09SeXFhK3lqZkZBWmYrajkxalczL09MNkM2ajNPMFRXV05aTlA1RjRldHFYZVBiN1lIMmkKOUcwb01jRUNnWUVBOG5qc1dUZnVmUVZYQVBLWHZGOW1UQUtsU0lzL3Vua2t3RVloWFh1WGtFRU9wOExEaVN2WQpwSnFzT3NUSlRRaE5mM0g0dWg4Rkl5SHFSb3BlS3VYYy9jSmFsRTFUejREZUN0d2c5R0xjVHpuaGV1RVVsTWhnCnNycVFucjFDTDJtRHd1MTFLL0w0MURHTkNaWFEyYWNmT1pYcCtLdkEzV0ZheVRLNzRDbHNKY2tDZ1lFQTVuMFMKYVlvQy9saEhHeGRqeDdOQTZUNDJVV1grMTFaRTZSSGRKWWtTa3NQWXdhYzlYUnFLWHlzcytrUnY4U2tUaUZMOAp5dnlRcjFyaWlGRWp6VkN2YjA5WjllRWw3UngyT3F3eEpISEJ3bFdKWUEvRFdLN3ZkbHdvZ21wbUhCVzdaQ1k1ClBRVVJSOWhmbC9TVk1selVjSFpyK1J1QmhqWElhTFd2KzdBM2pTY0NnWUFJeHArblN3THl1M0src2drVDVGQUwKaUR6N055OERUTWNydmw0T3lCNWdOanFWajlNTDcrNVRadFc4K3NwZVkyS0tybEZXU3pFZ2FHWFdUOFBBd2JrUgo1aXJwR3pOaFcwU3VGL0dKWnRxYWMzblp2TFBGL3NxaExXZDJsMXNCNUV2RWpsdWpUNVA1K2lFa3E2dDNkVGtJCkdJanpXeVFMM3k0dUFnd1N2TzBSSVFLQmdCVlZha2plZjF4dmExVjBtc1czTDhEbkF6d1JocjhEdXlrZmdDcWoKUDFiYVRjdk80UDBuSWJ1aFVXNXd1elBGSzR1b3NzRlBFMDFIeWtQM3pxcUlWMVNrTVoxeWs0SVk2bENQODVSOQord016eTUxYW1DZ3pPUExwb001QmJ1WVdsTnUyTmdJUjRBR1lZM0M3TUx3U240OHhSdGt0MUpWSmtSMHdBL1AxCjRZNXRBb0dCQUpHTlJKK3plRmdnR25OK25NdjNVa0ZTVDYxMEp3bi9QeWdUYTZPK3FZMlp0dHFITTBYKzRGM04KalpiSGpmTHlZZS9JaWZNMVpKR1M1ZUxTc0xjOFBjM0NaRUF3S05VUDkvQ2xsTCthamhibmwrdHRJOVBBZTFGeQorU1JSSVlPV1pZakFMNC82ZkNjL0UxY3g1OW9UVzR4eHBFRUtEck5rckxIY09iUTcxVVNuCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
	name: nginx-conf
data:  

server-conf: |
server {
    listen              80;
    listen              443 ssl;
    server_name         myapp.example.com;
    ssl_certificate     /etc/nginx/ssl/tls.crt;
    ssl_certificate_key /etc/nginx/ssl/tls.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    location / {
        root   /usr/share/nginx/html;
        index  index.html;
    }
}

Pod 생성

apiVersion: v1
kind: Pod
metadata:
	name: nginx-https-pod
	labels:
		app: nginx
spec:
	containers:
		- name: nginx
			image: nginx
			volumeMounts:
				- name: confvol
					mountPath: /etc/nginx/conf.d
				- name: secvol
					mountPath: /etc/nginx/ssl
	volumes:
		- name: confvol
			configMap:
				name: nginx-conf
		- name: secvol
			secret:
				name: nginx-secret

Service

apiVersion:
kind: Service
metadata:
  name: nginx-svc
spec:
  type: LoadBalancer
  selector:
	app: nginx
  ports:
	- name: http
		port: 80
		targetPort:80
	- name: httpsp
		port: 443
		targetPort: 443

Test

curl --insecure https://192.168.100.240
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>

728x90