ArgoCD 보안
지원 버전: ArgoCD v2.9+ 마지막 업데이트: 2026년 2월 22일
목차
SSO 통합
ArgoCD는 Dex를 통해 다양한 SSO 제공자와 통합할 수 있습니다.
OIDC (OpenID Connect)
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
url: https://argocd.example.com
oidc.config: |
name: Okta
issuer: https://myorg.okta.com
clientID: 0oaxxxxxxxxxx
clientSecret: $oidc.okta.clientSecret
requestedScopes:
- openid
- profile
- email
- groups
requestedIDTokenClaims:
groups:
essential: true
---
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
namespace: argocd
type: Opaque
stringData:
oidc.okta.clientSecret: your-client-secretSAML
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
url: https://argocd.example.com
dex.config: |
connectors:
- type: saml
id: okta
name: Okta SAML
config:
ssoURL: https://myorg.okta.com/app/xxx/sso/saml
caData: |
-----BEGIN CERTIFICATE-----
MIIDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-----END CERTIFICATE-----
redirectURI: https://argocd.example.com/api/dex/callback
usernameAttr: email
emailAttr: email
groupsAttr: groups
# 어설션 암호화 (선택)
# entityIssuer: https://argocd.example.com/api/dex/callbackLDAP / Active Directory
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
url: https://argocd.example.com
dex.config: |
connectors:
- type: ldap
id: ldap
name: LDAP
config:
host: ldap.example.com:636
insecureNoSSL: false
insecureSkipVerify: false
rootCA: /etc/dex/ldap-ca.crt
bindDN: cn=admin,dc=example,dc=com
bindPW: $dex.ldap.bindPW
usernamePrompt: Username
userSearch:
baseDN: ou=users,dc=example,dc=com
filter: "(objectClass=person)"
username: uid
idAttr: uid
emailAttr: mail
nameAttr: cn
groupSearch:
baseDN: ou=groups,dc=example,dc=com
filter: "(objectClass=groupOfNames)"
userMatchers:
- userAttr: DN
groupAttr: member
nameAttr: cnAzure AD
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
url: https://argocd.example.com
oidc.config: |
name: Azure AD
issuer: https://login.microsoftonline.com/TENANT_ID/v2.0
clientID: APPLICATION_ID
clientSecret: $oidc.azure.clientSecret
requestedScopes:
- openid
- profile
- email
requestedIDTokenClaims:
groups:
essential: true
# 그룹 필터링 (선택)
# groupsClaim: groupsAWS IAM Identity Center (SSO)
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
url: https://argocd.example.com
oidc.config: |
name: AWS IAM Identity Center
issuer: https://identitycenter.amazonaws.com/ssoins-xxxxxxxx
clientID: your-client-id
clientSecret: $oidc.aws.clientSecret
requestedScopes:
- openid
- profile
- email
requestedIDTokenClaims:
groups:
essential: trueadmin 계정 비활성화
SSO 설정 후 로컬 admin 계정을 비활성화합니다:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
admin.enabled: "false"시크릿 관리
Git 저장소에 시크릿을 안전하게 저장하는 방법입니다.
Sealed Secrets
Bitnami Sealed Secrets를 사용하면 암호화된 시크릿을 Git에 저장할 수 있습니다:
설치:
bash
# Sealed Secrets 컨트롤러 설치
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system
# kubeseal CLI 설치
brew install kubeseal # macOS사용:
bash
# 일반 Secret 생성
kubectl create secret generic my-secret \
--from-literal=password=supersecret \
--dry-run=client -o yaml > secret.yaml
# Sealed Secret으로 변환
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
# Git에 커밋
git add sealed-secret.yaml
git commit -m "Add sealed secret"Sealed Secret 예시:
yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: my-secret
namespace: production
spec:
encryptedData:
password: AgBy8hCM8FayQFfixS...encrypted...
template:
metadata:
name: my-secret
namespace: production
type: OpaqueExternal Secrets Operator
외부 시크릿 관리 시스템과 통합합니다:
설치:
bash
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespaceAWS Secrets Manager 연동:
yaml
# SecretStore 정의
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secrets-manager
namespace: production
spec:
provider:
aws:
service: SecretsManager
region: ap-northeast-2
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
---
# ExternalSecret 정의
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: production/database
property: username
- secretKey: password
remoteRef:
key: production/database
property: passwordHashiCorp Vault
Argocd Vault Plugin (AVP) 사용:
yaml
# Repo Server에 AVP 설치
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-repo-server
namespace: argocd
spec:
template:
spec:
containers:
- name: argocd-repo-server
volumeMounts:
- name: custom-tools
mountPath: /usr/local/bin/argocd-vault-plugin
subPath: argocd-vault-plugin
env:
- name: AVP_TYPE
value: vault
- name: AVP_AUTH_TYPE
value: k8s
- name: VAULT_ADDR
value: https://vault.example.com
initContainers:
- name: download-tools
image: alpine:3.18
command:
- sh
- -c
- |
wget -O /custom-tools/argocd-vault-plugin \
https://github.com/argoproj-labs/argocd-vault-plugin/releases/download/v1.17.0/argocd-vault-plugin_1.17.0_linux_amd64
chmod +x /custom-tools/argocd-vault-plugin
volumeMounts:
- name: custom-tools
mountPath: /custom-tools
volumes:
- name: custom-tools
emptyDir: {}AVP 사용 예시:
yaml
# AVP 플레이스홀더가 포함된 매니페스트
apiVersion: v1
kind: Secret
metadata:
name: db-secret
annotations:
avp.kubernetes.io/path: "secret/data/production/database"
type: Opaque
stringData:
username: <username>
password: <password>Application에서 AVP 플러그인 사용:
yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp.git
targetRevision: main
path: manifests
plugin:
name: argocd-vault-plugin
destination:
server: https://kubernetes.default.svc
namespace: productionSOPS (Secrets OPerationS)
SOPS 암호화 파일 사용:
yaml
# .sops.yaml (저장소 루트)
creation_rules:
- path_regex: .*\.enc\.yaml$
kms: arn:aws:kms:ap-northeast-2:123456789012:key/xxx
# 또는 age
# age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxbash
# 암호화
sops -e secret.yaml > secret.enc.yaml
# 복호화 (ArgoCD에서 자동)
sops -d secret.enc.yamlKSOPS (Kustomize + SOPS):
yaml
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
generators:
- secret-generator.yaml
---
# secret-generator.yaml
apiVersion: viaduct.ai/v1
kind: ksops
metadata:
name: secret-generator
files:
- secrets/db-secret.enc.yamlTLS 구성
자체 서명 인증서
bash
# 인증서 생성
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout argocd.key -out argocd.crt \
-subj "/CN=argocd.example.com"
# Secret 생성
kubectl create secret tls argocd-server-tls \
--cert=argocd.crt \
--key=argocd.key \
-n argocdLet's Encrypt (cert-manager)
yaml
# ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
---
# Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: argocd-server-tls
namespace: argocd
spec:
secretName: argocd-server-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- argocd.example.comIngress TLS
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server
namespace: argocd
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
ingressClassName: nginx
tls:
- hosts:
- argocd.example.com
secretName: argocd-server-tls
rules:
- host: argocd.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 443감사 로깅
감사 로그 활성화
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cmd-params-cm
namespace: argocd
data:
# 감사 로그 레벨
server.audit.enabled: "true"로그 형식
ArgoCD는 JSON 형식으로 감사 로그를 출력합니다:
json
{
"level": "info",
"action": "sync",
"application": "my-app",
"user": "admin@example.com",
"timestamp": "2025-02-21T10:30:00Z",
"message": "Application sync initiated"
}CloudWatch Logs 연동 (EKS)
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-server
namespace: argocd
spec:
template:
metadata:
annotations:
fluentbit.io/parser: json
spec:
containers:
- name: argocd-server
# 로그는 stdout으로 출력Fluent Bit ConfigMap:
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: amazon-cloudwatch
data:
fluent-bit.conf: |
[INPUT]
Name tail
Tag argocd.*
Path /var/log/containers/argocd-server*.log
Parser docker
DB /var/log/flb_argocd.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Refresh_Interval 10
[OUTPUT]
Name cloudwatch
Match argocd.*
region ap-northeast-2
log_group_name /aws/eks/argocd
log_stream_prefix audit-
auto_create_group true네트워크 보안
NetworkPolicy
yaml
# ArgoCD 컴포넌트 간 통신만 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: argocd-server
namespace: argocd
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: argocd-server
policyTypes:
- Ingress
- Egress
ingress:
# Ingress Controller에서 접근
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
- protocol: TCP
port: 8083
egress:
# Repo Server 접근
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: argocd-repo-server
ports:
- protocol: TCP
port: 8081
# Redis 접근
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: argocd-redis
ports:
- protocol: TCP
port: 6379
# Dex 접근
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: argocd-dex-server
ports:
- protocol: TCP
port: 5556
# DNS
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# Kubernetes API
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- protocol: TCP
port: 443
---
# Repo Server NetworkPolicy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: argocd-repo-server
namespace: argocd
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: argocd-repo-server
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: argocd-server
- podSelector:
matchLabels:
app.kubernetes.io/name: argocd-application-controller
ports:
- protocol: TCP
port: 8081
egress:
# Git 저장소 접근 (HTTPS)
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- protocol: TCP
port: 443
- protocol: TCP
port: 22
# Redis 접근
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: argocd-redis
ports:
- protocol: TCP
port: 6379저장소 자격 증명
HTTPS (사용자명/비밀번호)
yaml
apiVersion: v1
kind: Secret
metadata:
name: repo-creds-github
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
type: Opaque
stringData:
type: git
url: https://github.com/myorg/myrepo.git
username: git
password: ghp_xxxxxxxxxxxxxxxxxxxx # Personal Access TokenSSH 키
yaml
apiVersion: v1
kind: Secret
metadata:
name: repo-creds-ssh
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
type: Opaque
stringData:
type: git
url: git@github.com:myorg/myrepo.git
sshPrivateKey: |
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
...
-----END OPENSSH PRIVATE KEY-----GitHub Apps
yaml
apiVersion: v1
kind: Secret
metadata:
name: repo-creds-github-app
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
type: Opaque
stringData:
type: git
url: https://github.com/myorg
githubAppID: "123456"
githubAppInstallationID: "12345678"
githubAppPrivateKey: |
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA...
-----END RSA PRIVATE KEY-----자격 증명 템플릿
여러 저장소에 동일한 자격 증명을 사용할 때:
yaml
apiVersion: v1
kind: Secret
metadata:
name: creds-template-github
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repo-creds # repository가 아닌 repo-creds
type: Opaque
stringData:
type: git
url: https://github.com/myorg # 패턴 매칭
username: git
password: ghp_xxxxxxxxxxxxxxxxxxxxGPG 서명 검증
GPG 키 등록
bash
# 공개 키 내보내기
gpg --armor --export KEY_ID > public-key.asc
# ArgoCD에 키 등록
argocd gpg add --from public-key.asc
# 또는 선언적으로
kubectl create secret generic argocd-gpg-keys-secret \
--from-file=public-key.asc \
-n argocd프로젝트에서 서명 검증 활성화
yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: production
namespace: argocd
spec:
description: Production with GPG verification
sourceRepos:
- 'https://github.com/myorg/production-*'
destinations:
- namespace: 'prod-*'
server: https://prod-cluster.example.com
# 서명 검증 필수
signatureKeys:
- keyID: 4AEE18F83AFDEB23 # GPG 키 ID
- keyID: ABCD1234EFGH5678
# GPG 키 목록
sourceNamespaces:
- argocd커밋 서명
bash
# Git 커밋 서명 설정
git config --global user.signingkey KEY_ID
git config --global commit.gpgsign true
# 서명된 커밋
git commit -S -m "Signed commit message"
# 서명 확인
git log --show-signature다음 단계
알림: 보안 이벤트에 대한 알림을 구성하세요.
모범 사례: 보안 모범 사례를 학습하세요.
프로젝트와 RBAC: RBAC과 함께 보안을 강화하세요.
참고 자료
퀴즈
이 장에서 배운 내용을 테스트하려면 보안 퀴즈를 풀어보세요.