CI/CD 5주차(Argo CD) - 접근제어, SSO

2025. 11. 15. 10:00CICD

실습 환경 배포

kind 배포

kind create cluster --name myk8s --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  labels:
    ingress-ready: true
  extraPortMappings:
  - containerPort: 80
    hostPort: 80
    protocol: TCP
  - containerPort: 443
    hostPort: 443
    protocol: TCP
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
  - containerPort: 30002
    hostPort: 30002
  - containerPort: 30003
    hostPort: 30003
EOF

 

kube-ops-view 배포

# helm 레포지토리 추가
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/

# kube-ops-view 배포
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30001 --set env.TZ="Asia/Seoul" --namespace kube-system

# kube-ops-view 접속 URL 접속 확인
open "http://127.0.0.1:30001/#scale=2"

 

ingress-nginx 배포

 

노드 라벨 확인

# 마스터 노드 라벨 확인
kubectl get nodes myk8s-control-plane -o jsonpath={.metadata.labels} | jq

 

kubectl get nodes myk8s-control-plane -o jsonpath={.metadata.labels} | jq
{
  "beta.kubernetes.io/arch": "arm64",
  "beta.kubernetes.io/os": "linux",
# 추가한 Label 확인
  "ingress-ready": "true",
  "kubernetes.io/arch": "arm64",
  "kubernetes.io/hostname": "myk8s-control-plane",
  "kubernetes.io/os": "linux",
  "node-role.kubernetes.io/control-plane": ""
}

 

배포

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

# 배포 확인
kubectl get deploy,svc,ep ingress-nginx-controller -n ingress-nginx
kubectl describe -n ingress-nginx deployments/ingress-nginx-controller

myk8s-control-plane의 iptables 규칙 확인

DNAT 설정 - myk8s-control-plane으로 80,443 포트로 트래픽이 들어올 경우 10.244.0.8 IP가 할당된 Pod의 80,443포트로 포워딩

 

(ingress-nginx)- SSL Passthrough flag 활성화

해당 설정을 활성화 하는 목적은 호화된 트래픽(TLS/SSL)을 인그레스 컨트롤러에서 복호화(해독)하지 않고, 원본 그대로 백엔드 파드(Pod)까지 전달하기 위해서다.(활성화 하지 않을 경우 Too Many Redirect 발생)

# ingress-nginx-controller 수정
KUBE_EDITOR="nano" kubectl edit -n ingress-nginx deployments/ingress-nginx-controller

 

 

ArgoCD 설치

TLS 통신 과정(Client > ingress > Argo CD Server > Secret)

[출처]CI/CD Study [1기] - 5주차 Argo CD 2/3 (gasidaseo)

 

TLS 인증서 발급

# 공통 이름 argocd.example.com
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout argocd.example.com.key \
  -out argocd.example.com.crt \
  -subj "/CN=argocd.example.com/O=argocd"
  
# 인증서 확인
openssl x509 -noout -text -in argocd.example.com.crt

 

생성된 TLS 적용을 위해 secret 생성

# 네임스페이스 생성
kubectl create ns argocd

# TLS 시크릿 생성
kubectl -n argocd create secret tls argocd-server-tls \
--cert=argocd.example.com.crt \
--key=argocd.example.com.key

 

(ArgoCD) - SSL-PassThrough 적용 및 배포

cat <<EOF > argocd-values.yaml
global:
  domain: argocd.example.com

# TLS certificate configuration via cert-manager
certificate: 
  enabled: true

server:
  ingress:
    enabled: true
    ingressClassName: nginx
    annotations:
      nginx.ingress.kubernetes.io/force-ssl-redirect: "true" # 강제 리다이렉트
      nginx.ingress.kubernetes.io/ssl-passthrough: "true" # SSL-Passthrough
    tls: true
EOF

helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd --version 9.0.5 -f argocd-values.yaml --namespace argocd

 

(Argo CD) - 서비스 확인

kubectl get pod,ingress,svc,ep,secret,cm -n argocd

 

도메인 설정

 

접속 확인

# 도메인 curl
curl -vk https://argocd.example.com/
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller
kubectl -n argocd logs deploy/argocd-server

# 최초 비밀번호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo


# UI 접속(강제 리다이렉트 확인 필요)
open "http://argocd.example.com"

도메인 및 강제 리다이렉트 확인

 

TLS 인증서 확인(발급 기관 : argocd.example.com)

 

(Argo CD) - CLI 접속 확인

argocd login argocd.example.com --insecure
ID/PW 입력

 

(Argo CD) - CLI 명령어 실행 확인

 


선언적 사용자

- Argo CD에서 선언적 사용자란 핵심 설정 파일인 argocd-cm(configmap) 내에 코드로 직접 정의하고 관리하는 로컬 사용자 계정을 의미한다.

- 선언적 사용자에게 실제 권한은 RBAC(Role-Based Access Control)으로 설정

 

선언적 방식 사용 목적

- Argo CD를 다른 시스템으로 전환할 경우 argocd-cm YAML파일만 적용하면 기존에 정의된 모든 자동화 계정들 사용 가능

- GitOps 파이프라인을 통해 사용자 계쩡의 생성 및 변경을 자동화 가능

 

관리자(admin) 계정

- Argo CD 생성 시 기본적으로 관리자 계정 생성 ( 전체 액세스 권한 부여 )

- admin 비밀번호는 Secret에 저장

kubectl get secret -n argocd argocd-initial-admin-secret --context kind-myk8s -o jsonpath='{.data.password}' | base64 -d

 

 

관리자(admin) 패스워드 변경

# 현재 접속 중인 계정 패스워드 변경
argocd account update-password
# 현재 패스워드 입력
# 변경 패스워드 입력
# 변경 패스워드 재입력

# 다른 계정 패스워드 변경
argocd account update-password --acount {user명}

 

 

(중요!) 관리자 계정은 초기 구축 이후 로컬 사용자 계정이나 SSO 통합을 구성하는 것이 보안성 면에서는 좋음.

아래 argocd-cm configmap에서 정의된 admin.enabled를 true > false로 변경하면 admin 계정 비활성화

 

일반(user) 계정

argocd-cm 수정

kubectl get cm -n argocd argocd-cm -o yaml
KUBE_EDITOR="nano"  kubectl edit cm -n argocd argocd-cm

# 내용 추가
accounts.alice: apikey, login

# 계정 확인
argocd account list

apikey - API key를 통한 호출 허용

login - UI 접속 허용

 

계정 패스워드 변경

argocd account update-password --account alice --curent-password qwe12345 --new-password alice12345

# 변경 확인
kubectl get secret -n argocd argocd-secret -o jsonpath='{.data}' | jq

 

accounts.alice.password는 base64로 디코딩해도 실제 비밀번호가 나오지 않는다.

 

위와 같이 $2a$~로 표시되는데 Argo CD가 보안을 위해 실제 비밀번호를 bcrypt 해시로 변환하여 저장한 값으로 실제 비밀번호를 Secret을 통해서 확인하는 것은 불가능하다.

 

애플리케이션 배포 테스트

Admin 계정 - 애플리케이션 배포

cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    helm:
      valueFiles:
      - values.yaml
    path: helm-guestbook
    repoURL: https://github.com/argoproj/argocd-example-apps
    targetRevision: HEAD
  syncPolicy:
    automated:
      enabled: true
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
  destination:
    namespace: guestbook
    server: https://kubernetes.default.svc
EOF

 

배포 확인

kubectl get applications -n argocd guestbook
kubectl get applications -n argocd guestbook -o yaml | kubectl neat | yq
kubectl get pod,svc,ep -n guestbook

 

Argo CD UI 확인 - admin 계정

애플리케이션 확인

Argo CD UI 확인 - alice 계정

 

alice 계정은 생성 이후 별도에 권한을 부여하지 않았으며, 권한이 부여되지 않은 경우 기본 정책(policy.default)에 따라 argoCD에 대한 권한이 결졍된다.

 

권한 부여(RBAC)

- RBAC 기능은 Argo CD 리소스에 대한 액세스를 제한

- admin 사용자는 SuperUser이며, 모든 액세스 권한 부여

- RBAC을 사용하려면 SSO 구성 or 하나 이상의 로컬 사용자 필요

- SSO 또는 로컬 사용자를 구성한 후에는 추가 RBAC 역할을 정의하고 SSO 그룹 또는 로컬 사용자를 역할에 매핑

 

 

 

기본 내장 역할 : Argo CD에는 두 가지 사전 정의된 역할이 있지만 RBAC 구성을 사용하면 역할과 그룹을 정의할 수 있습니다.

  • role:readonly : 모든 리소스에 대한 읽기 전용 액세스
  • role:admin : 모든 리소스에 대한 무제한 액세스

 

RBAC 설정

kubectl get cm -n argocd argocd-rbac-cm -o jsonpath='{.data}' | jq

KUBE_EDITOR="nano" kubectl edit cm -n argocd argocd-rbac-cm

# 기존 - policy.default: ""
# 변경 - policy.default: "role:readonly"

 

Argo CD UI 확인 - alice 계정

애플리케이션 확인
클러스터 확인

 

Argo CD CLI - alice 계정 로그인

argocd login argocd.example.com --insecure --username alice
# User - alice, Password - alice12345

클러스터 및 애플리케이션 조회

 

admin 계정 비활성화

KUBE_EDITOR="nano"  kubectl edit cm -n argocd argocd-cm

argocd account list

admin.enabled: "true" > "false" 변경

 

admin 계정 접속 확인

접속 불가 확인


서비스 어카운트

- CI/CD 파이프라인과 같은 자동화를 시스템에 인증하는 데 사용하는 계정

- 사용자를 비활성화하거나 권한을 제어하면 파이프라인이 실패할 수 있기 때문에 사용자와 연결

- 엄격하게 권한을 제한해야 하고 파이프라인에서 수행하는 것 이상의 권한이 있으면 안 된다.

- ArgoCD에서 서비스 어카운트 생성 방법(API 키만을 사용하는 로컬 사용자[로그인 기능 제거], 프로젝트 역할을 사용하고 그 역할에 토큰을 할당)

 

서비스 어카운트 생성 및 RBAC 설정(api키만 생성)

KUBE_EDITOR="nano"  kubectl edit cm -n argocd argocd-cm

# accounts.gitops-ci : apiKey 내용 추가

# 생성 확인
acrocd account list

 

계정 토큰 생성 

argocd account generate-token -a gitops-ci

 

PermissionDenied 에러 발생

 

현재 로그인 되어 있는 alice 계정에는 별도에 권한을 설정하지 않았기에 토큰이 생성되지 않는다.

권한 설정은 아래와 같이 진행한다.

# p : 권한 정책 설정, g : 사용자 또는 그룹에 역할을 연결 할 때 사용
KUBE_EDITOR="nano"  kubectl edit cm -n argocd argocd-rbac-cm
  policy.csv: |
    p, role:user-update, accounts, update, *, allow # 정책 설정(user-update 역할을 통해 부여된 계정이 업데이트 권한 허용)
    p, role:user-update, accounts, get, *, allow # 정책 설정(user-update 역할을 통해 부여된 계정이 조회 권한 허용)
    g, alice, role:user-update # 그룹 정의(alice 계정에 user-update 정책 부여)
    

# 토큰 재생성 시도
argocd account generate-token -a gitops-ci

# 토큰 작동 확인
argocd account get-user-info --auth-token {토큰 값}

토큰 생성 및 값 확인
토큰 작동 확인

 

Project Role과 Token

- 프로젝트 역할은 서비스 어카운트에서 사용할 수 있는 두 번째 옵션

- 애플리케이션 프로젝트는 역할을 통해 애플리케이션 정의에 일부 제약 조건을 적용하는 방식

- 리포지터리, 대상 클러스터나 배포할 수 있는 네임스페이스를 지정할 수 있고, 설치할 수 있는 리소스 유형을 필터링

 

기본 프로젝트 권한 확인

kubectl get appprojects.argoproj.io -n argocd default -o yaml | k neat | yq

 

Argo CD 생성 이후 기본으로 제공되는 프로젝트는 별도의 제약 사항 없다. 

 

- clusterResourceWhitelist : 클러스터 범위 내 리소스에 대한 모든 그룹 및 종류에 대한 관리 가능

- destinations : 모든 네임스페이스 및 워커 노드들에 대해서 애플리케이션 배포 가능

- sourceRepos : 모든 Git 저장소를 소스 저장소로 사용 가능

 

애플리케이션 프로젝트 생성(프로젝트 역할 설정)

#
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: sample-apps
  namespace: argocd
spec:
  roles:
    - name: read-sync
      description: read and sync privileges
      policies:
        - p, proj:sample-apps:read-sync, applications, get, sample-apps/*, allow
        - p, proj:sample-apps:read-sync, applications, sync, sample-apps/*, allow
  clusterResourceWhitelist:
    - group: '*'
      kind: '*'
  description: Project to configure argocd self-manage application
  destinations:
    - namespace: test
      server: https://kubernetes.default.svc
  sourceRepos:
    - https://github.com/argoproj/argocd-example-apps.git
EOF


#
kubectl get appproject -n argocd

 

프로젝트 권한 설명

- 사용자 역할(spec.roles)

>> read-sync 역할을 가진 사용자는 sample-apps 프로젝트에 속한 모든 애플리케이션에 get,sync 작업을 허용

 

- 프로젝트 역할(제한)

>> 모든 클러스터 리소스에 대한 그룹과 종류에 대한 배포가 가능하며, test 네임스페이스에서만 리소스 배포가 가능하며, argocd-example-apps.git만 소스 저장소로 사용 가능

 

Argo CD - UI 확인

 

 

sample-apps 프로젝트에 애플리케이션 배포

cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: pre-post-sync
  namespace: argocd
  finalizers:
  - resources-finalizer.argocd.argoproj.io
spec:
  project: sample-apps
  source:
    path: pre-post-sync
    repoURL: https://github.com/argoproj/argocd-example-apps
    targetRevision: master
  destination:
    namespace: test
    server: https://kubernetes.default.svc
  syncPolicy:
    automated:
      enabled: false
    syncOptions:
    - CreateNamespace=true
EOF

# 애플리케이션 조회
argocd app list

 

수동 동기화 실행(실패 - 권한 에러 발생)

argocd app sync argocd/pre-post-sync

 

rbac-cm 정책 수정(read,sync 권한 추가)

KUBE_EDITOR="nano"  kubectl edit cm -n argocd argocd-rbac-cm

# 현재 권한 
# apiVersion: v1
# data:
#  policy.csv: |
#     p, role:user-update, accounts, update, *, allow
#     p, role:user-update, accounts, get, *, allow
#     g, alice, role:user-update

# 변경 권한
# apiVersion: v1
# data:
#  policy.csv: |
#     p, role:user-update, accounts, update, *, allow
#     p, role:user-update, accounts, get, *, allow
#(추가)p, role:user-update, projects, update, sample-apps, allow
#     g, alice, role:user-update

 

 

역할 토큰 생성

argocd proj role create-token sample-apps read-sync


Argo CD - SSO

[참고]OpenID Connect authorization code flow simplied

 

ArgoCD - admin 계정 활성화

# argocd-cm 수정
KUBE_EDITOR="nano" kubectl edit cm -n argocd argocd-cm

false > true 설정

ArgoCD CLI - admin 로그인

argocd login argocd.example.com --username admin --password qwe12345 --insecure

설치 - Kubernetes

# 관리자 ID : admin, 관리자 PW : admin
docker run -d \
  -e KEYCLOAK_ADMIN=admin \
  -e KEYCLOAK_ADMIN_PASSWORD=admin \
  -p 8080:8080 \
  --name dev-keycloak \
  quay.io/keycloak/keycloak:22.0.0 start-dev
  
# 확인
docker ps

# 로그 확인
docker logs dev-keycloak

# 자바 버전 확인
docker exec -it dev-keycloak java --version

docker images
docker history quay.io/keycloak/keycloak:22.0.0 --no-trunc --format json | jq

# /opt/keycloak/bin 경로 확인 및 실행
docker exec -it dev-keycloak ls -l /opt/keycloak/bin
docker exec -it dev-keycloak cat /opt/keycloak/bin/kc.sh


# 기본 정보 및 접속 확인
docker exec -it dev-keycloak id
open http://localhost:8080/admin

#접속 모니터링
```bash
# 도커에서 컨테이너로 Keycloak 실행
# 기본 관리자 계정이 제공되지 않아, 환경 변수로 초기 관리자 계정 생성
docker run -d -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin **--net host** --name dev-keycloak quay.io/keycloak/keycloak:22.0.0 **start-dev**

# 확인
**docker ps**
CONTAINER ID   IMAGE                              COMMAND                  CREATED         STATUS         PORTS                                                   NAMES
db56c9925eff   quay.io/keycloak/keycloak:22.0.0   "/opt/keycloak/bin/k…"   7 seconds ago   Up 6 seconds   0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp, 8443/tcp   dev-keycloak

**docker logs dev-keycloak**
...
2025-10-13 13:52:35,966 INFO  [org.keycloak.services] (main) KC-SERVICES0050: **Initializing master realm**
2025-10-13 13:52:36,845 INFO  [io.quarkus] (main) Keycloak 22.0.0 on JVM (powered by Quarkus 3.2.0.Final) started in 4.856s. Listening on: http://0.0.0.0:8080
2025-10-13 13:52:36,845 INFO  [io.quarkus] (main) **Profile dev activated**.
2025-10-13 13:52:36,845 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, jdbc-h2, jdbc-mariadb, jdbc-mssql, jdbc-mysql, jdbc-oracle, jdbc-postgresql, keycloak, logging-gelf, micrometer, narayana-jta, reactive-routes, resteasy, resteasy-jackson, smallrye-context-propagation, smallrye-health, vertx]
2025-10-13 13:52:36,941 INFO  [org.keycloak.services] (main) KC-SERVICES0009: Added **user** 'admin' to **realm** 'master'
2025-10-13 13:52:36,943 WARN  [org.keycloak.quarkus.runtime.KeycloakMain] (main) Running the server in **development mode**. DO NOT use this configuration in production.

docker exec -it dev-keycloak **java --version**
openjdk 17.0.8 2023-07-18 LTS

docker images
**docker history quay.io/keycloak/keycloak:22.0.0 --no-trunc --format json | jq**
{
  "Comment": "buildkit.dockerfile.v0",
  "CreatedAt": "2023-08-10T00:27:54+09:00",
  "CreatedBy": "**ENTRYPOINT** [\"**/opt/keycloak/bin/kc.sh**\"]",
  "CreatedSince": "2 years ago",
  "ID": "sha256:456b66461f4b63c7a42de1981b8f72052087c84df460b57db013c7d6fc7aed3e",
  "Size": "0B"
...

docker exec -it dev-keycloak **ls -l /opt/keycloak/bin**
docker exec -it dev-keycloak **cat /opt/keycloak/bin/kc.sh**

docker exec -it dev-keycloak **id**
uid=1000(keycloak) gid=0(root) groups=0(root)

# admin 웹 콘솔 접속 : admin / admin
**open http://localhost:8080/admin**

# 로그 모니터링 걸어두기
docker logs dev-keycloak -f

docker ps
docker images
keycloak ID 확인

KeyCloak - 접속 확인

초기 화면
admin/admin 로그인

 

KeyCloak - 일반 유저 생성

bob 계정 생성
bob 계정 패스워드 설정

 

KeyCloak - ArgoCD 연동 Client 생성

 

Key Cloak - Client Credential 복사 및 저장

 

ArgoCD - OIDC 설정

# oidc key의 값으로 아까 생성된 key-cloak client credential 입력
kubectl -n argocd patch secret argocd-secret --patch='{"stringData": { "oidc.keycloak.clientSecret": "LO7dCzcBsXDgcVXdjvPFkHrSCC3C08WP" }}'

 

argocd-secret의 keycloak client key 값 확인

 

Argocd - argocd-cm 수정

#  argocd-cm 내용 추가
KUBE_EDITOR="nano"  kubectl edit cm -n argocd argocd-cm

# 해당 내용 추가
data:
  url: https://argocd.example.com # 맨 아래 있음
  oidc.config: |
    name: Keycloak
    issuer: http://192.168.254.110:8080/realms/master
    clientID: argocd
    clientSecret: mV3IZO3nmHoZr3BBC37UpdrMSMkF9Umt
    requestedScopes: ["openid", "profile", "email"]

ArgoCD - 재기동

kubectl rollout restart deploy argocd-server -n argocd

 

ArgoCD - Keycloak 로그인

KEYKCLOAK 로그인 버튼 생성 확인
bob/bob123 계정으로 로그인

 

KeyClock - 세션 현황 확인

세션 현황 확인
Argo CD - bob 계정 정보 확인
KeyCloak - bob ID 값 확인

 

'CICD' 카테고리의 다른 글

CI/CD 6주차(Argo CD)[3] - App of Apps, ApplicationSet  (0) 2025.11.22
CI/CD 5주차(Argo CD)[2] - Argo Rollout  (0) 2025.11.15
CI/CD 4주차(Argo CD)  (0) 2025.11.09
CI/CD 3주차(Jenkins + ArgoCD + gogs[Repo])  (0) 2025.11.01
CI/CD 2주차  (0) 2025.10.26