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>