설정
Cert-Manager
먼저 Cert-Manager에서 사용하는 개념을 정리하면 다음과 같다.
개념 | 설명 |
---|---|
Issuer | 네임스페이스 범위에서 인증서를 발급할 수 있게 해주는 리소스 |
ClusterIssuer | 클러스터 전체 범위에서 인증서 발급 가능 |
Certificate | 실제로 발급받고자 하는 인증서 정의 |
issuerRef | 어떤 Issuer를 사용할지 지정 |
- SelfSigned CA 발급을 위한 ClusterIssuer 생성
# selfsigned-clusterissuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-cluster-issuer
spec:
selfSigned: {}
- CA Certificate 발급
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: root-ca
namespace: cert-manager
spec:
isCA: true
commonName: "Private CA Cert"
secretName: root-ca-secret
duration: 8760h # 1년
privateKey:
algorithm: RSA
size: 2048
issuerRef:
name: selfsigned-cluster-issuer
kind: ClusterIssuer
- CA를 통해 발급한 인증서의 Issuer 등록
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: ca-cluster-issuer
spec:
ca:
secretName: root-ca-secret
- GitLab 인증서 발급 (SelfSigned Root CA)
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: gitlab-wildcard-cert
namespace: gitlab
spec:
secretName: gitlab-wildcard-tls
commonName: "*.local.example"
dnsNames:
- "*.local.example"
- "gitlab.example.com" # 루트 도메인도 포함하려면 명시적으로 작성
issuerRef:
name: ca-cluster-issuer
kind: ClusterIssuer
- GitLab Workspace 인증서 발급 (SelfSigned Root CA)
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: gitlab-workspace-wildcard-cert
namespace: gitlab-workspaces
spec:
secretName: gitlab-workspace-wildcart-tls
commonName: "*.workspace.local.example"
dnsNames:
- "*.workspace.local.example"
- "workspace.local.example" # 루트 도메인도 포함하려면 명시적으로 작성
issuerRef:
name: ca-cluster-issuer
kind: ClusterIssuer
Trust-Manager
- Root CA Bundle 생성 (각 Namespace 배포)
apiVersion: trust.cert-manager.io/v1alpha1
kind: Bundle
metadata:
name: ca-pemstore
spec:
sources:
- useDefaultCAs: true
- inLine: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
target:
configMap:
key: "ca-certificates.crt"
Kyverno
- ClusterPolicy 적용 (Admission Webhook)
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-ca-certificates-volume
spec:
background: false
rules:
- name: add-ca-certificates
match:
resources:
kinds:
- Deployment
- StatefulSet
- DaemonSet
- Pod
mutate:
patchStrategicMerge:
spec:
initContainers:
- (name): "*"
volumeMounts:
- name: etc-ssl-certs
mountPath: /etc/ssl/certs/ca-certificates.crt
subPath: ca-certificates.crt
readOnly: true
containers:
- (name): "*"
volumeMounts:
- name: etc-ssl-certs
mountPath: /etc/ssl/certs/ca-certificates.crt
subPath: ca-certificates.crt
readOnly: true
volumes:
- name: etc-ssl-certs
configMap:
name: ca-pemstore
Windows 적용 (Client)
- CA.Cert 추출하기 (CA Certificate 발급 시 생성됐던 Secret)
# ca.crt
$ kubectl get secret root-ca-secret -n cert-manager -o jsonpath='{.data.ca\.crt}' | base64 --decode > ca.crt
$ cat ca.crt
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
- Windows 인증서 관리 매니저 실행
certmgr.msc
- 발급한 Root CA 인증서 추가


확인
- Kyverno Admission Controller
앞서 생성한 Kyverno Policy (add-ca-certificates-volume)가 적용되어 Webhook - Mutation 단계에서 Resource를 수정한다.
$ k get po -n kyverno -l app.kubernetes.io/component=admission-controller
NAME READY STATUS RESTARTS AGE
kyverno-admission-controller-df7b67cf-7q629 1/1 Running 2 (6h8m ago) 3d21h
$ k logs kyverno-admission-controller-df7b67cf-7q629 -n kyverno
...
2025-03-24T02:03:22Z INF github.com/kyverno/kyverno/pkg/webhooks/resource/mutation/mutation.go:136 > mutation rules from policy applied successfully URLParams= clusterroles=["cluster-admin","system:basic-user","system:discovery","system:public-info-viewer"] gvk="apps/v1, Kind=Deployment" gvr={"group":"apps","resource":"deployments","version":"v1"} kind=Deployment logger=webhooks/resource/mutate name=gitlab-registry namespace=gitlab operation=CREATE policy=add-ca-certificates-volume resource.gvk="apps/v1, Kind=Deployment" roles=[] rules=["add-ca-certificates"] uid=b9599936-0a53-4c13-9c42-2f6a6be198af user={"groups":["kubeadm:cluster-admins","system:authenticated"],"username":"kubernetes-admin"} v=0
2025-03-24T02:03:22Z INF github.com/kyverno/kyverno/pkg/webhooks/resource/mutation/mutation.go:136 > mutation rules from policy applied successfully URLParams= clusterroles=["cluster-admin","system:basic-user","system:discovery","system:public-info-viewer"] gvk="apps/v1, Kind=Deployment" gvr={"group":"apps","resource":"deployments","version":"v1"} kind=Deployment logger=webhooks/resource/mutate name=gitlab-gitlab-shell namespace=gitlab operation=CREATE policy=add-ca-certificates-volume resource.gvk="apps/v1, Kind=Deployment" roles=[] rules=["add-ca-certificates"] uid=831bc9f5-29cb-4644-a55e-f34552fb5e7d user={"groups":["kubeadm:cluster-admins","system:authenticated"],"username":"kubernetes-admin"} v=0
...
- 수정된 Resource 살펴보기
Kyverno Policy에 설정한 대로 “etc-ssl-certs” Volume이 추가되어 생성되었다.
Name: gitlab-gitlab-shell-f56dd8dbc-7w56x
Namespace: gitlab
Priority: 0
Service Account: default
Node: test-worker/172.18.0.2
Labels: app=gitlab-shell
chart=gitlab-shell-8.8.1
Controlled By: ReplicaSet/gitlab-gitlab-shell-f56dd8dbc
Containers:
gitlab-shell:
Container ID: containerd://c6c49e0b2d1f86c2e6b6adaa6aa8591500fc0da028fee94fdd46e06dd7be8fab
Image: registry.gitlab.com/gitlab-org/build/cng/gitlab-shell:v14.39.0
Image ID: registry.gitlab.com/gitlab-org/build/cng/gitlab-shell@sha256:466e09ede4852a497fd48190afb9653a94cc7008133ff174aee53023c48069a9
Port: 2222/TCP
Host Port: 0/TCP
State: Running
Started: Mon, 24 Mar 2025 11:14:41 +0900
Ready: True
Restart Count: 0
Requests:
cpu: 0
memory: 6M
Liveness: exec [/scripts/healthcheck] delay=10s timeout=3s period=10s #success=1 #failure=3
Readiness: tcp-socket :2222 delay=10s timeout=3s period=5s #success=1 #failure=2
Environment:
GITALY_FEATURE_DEFAULT_ON: 1
CONFIG_TEMPLATE_DIRECTORY: /etc/gitlab-shell
CONFIG_DIRECTORY: /srv/gitlab-shell
KEYS_DIRECTORY: /etc/gitlab-secrets/ssh
SSH_DAEMON: openssh
TZ: UTC
Mounts:
/etc/gitlab-secrets from shell-secrets (ro)
/etc/gitlab-shell from shell-config (rw)
/etc/krb5.conf from shell-config (ro,path="krb5.conf")
/etc/pki/ca-trust/extracted/pem from etc-pki-ca-trust-extracted-pem (ro)
/etc/ssh/sshd_config from sshd-config (ro,path="sshd_config")
/etc/ssl/certs/ from etc-ssl-certs (ro)
Volumes:
shell-config:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: gitlab-gitlab-shell
Optional: false
sshd-config:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: gitlab-gitlab-shell-sshd
Optional: false
shell-init-secrets:
Type: Projected (a volume that contains injected data from multiple sources)
SecretName: gitlab-gitlab-shell-host-keys
SecretOptionalName: <nil>
SecretName: gitlab-gitlab-shell-secret
SecretOptionalName: <nil>
shell-secrets:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium: Memory
SizeLimit: <unset>
etc-ssl-certs:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium: Memory
SizeLimit: <unset>
etc-pki-ca-trust-extracted-pem:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium: Memory
SizeLimit: <unset>
- TLS 확인
정상적으로 TLS HandShaking 확인.
CAfile: /etc/ssl/certs/ca-certificates.crt (Kyverno Policy에서 설정한 volumeMount 위치)
(Client hello → Server hello → Finished)
$ kubectl run tmp-shell --rm -i --tty --image nicolaka/netshoot
# gitlab.local.example, *.local.example 도메인에 대해서 인증서를 발급받았음
$ curl -v https://gitlab.local.example
* Host gitlab.local.example:443 was resolved.
* IPv6: (none)
* IPv4: 172.18.0.2
* Trying 172.18.0.2:443...
* Connected to gitlab.local.example (172.18.0.2) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / x25519 / RSASSA-PSS
후기

Kyverno ClusterPolicy를 사용해서 생성되는 리소스에 대해서 CA 인증서를 추가하도록 Admission WebHook을 통해 간단하게 구성해보았다.
TLS, mTLS는 서비스 메시 도구 (ex. Istio)를 사용해서 구성하는 방안이 더 깔끔한 방안이 될 것 같다.
이번에 Kyverno의 ClusterPolicy를 통해서 Admission Webhook을 따로 구성하지 않아도 간단한 Yaml 구성을 통해 수행할 수 있어 보안 정책을 수립할 때 괜찮은 도구인 것 같다.
'Kubernetes' 카테고리의 다른 글
Self Sign 인증서 적용하기 - 설치 (0) | 2025.03.24 |
---|---|
인증서를 무료로 관리해보자(Cert-manager + Let’s Encrypt) (0) | 2025.01.12 |
VKE - Vultr Kubernetes Engine (3) | 2025.01.12 |
kind(Kubernetes in Docker) (4) | 2025.01.12 |
Kubernetes Workload Resources(Daemonset) (7) | 2023.12.03 |