본래 Argo Workflow는 Oauth2.0 인증을 수행하기 위해 Argo CD에 내장되어 있는 DEX를 사용하게끔 되어 있습니다. (이하 Argo CD DEX)
하지만 Argo CD DEX를 사용하지 않고 Argo Workflow에서 자체적으로 DEX를 사용해 Oauth2.0 인증을 수행해야 하는 상황이 존재합니다.
예를 들면 Argo CD와 별개의 Identity Service를 운용하고자 하며, Argo Workflow 자체 OIDC 인증이 지원하지 않는 기능을 사용해야 할 때(EX. Google Groups), Argo Workflow만의 DEX를 구축해야 합니다.
이번 글에서는 Argo Workflow의 자체 DEX를 사용해 인증을 수행하는 방법에 대해 알아보겠습니다.
1. Overview
DEX는 아래와 같은 기능을 수행합니다.
- LDAP, SAML, 기존 IdP와 같은 인증을 처리해주는 Identity Provider 역할 대행
- Client와 IdP 사이의 Connector 역할을 함으로써 Client가 인증 구현에 신경쓰지 않고 관련 로직을 DEX에게 전가 가능
- 기존 IdP가 지원하지 않는 추가적인 기능 구현
Argo Workflow는 Oauth2.0 인증을 구현하기 위해 Argo CD DEX를 이용할 수 있으며, 자체 인증 기능도 사용할 수 있지만, 아래와 같은 문제점들이 존재합니다.
- Argo CD DEX에 인증 기능을 전가할시, SPOF(Single Point of Failure)의 위험
- Argo Workflow 자체 인증 기능이 지원하지 않는 IdP 존재 (Azure OICD, Github 등..)
- Argo Workflow 자체 인증 기능이 지원하지 않는 기능 존재 (Google Groups 지원 등..)
Argo Workflow의 자체 Standalone DEX를 구축하면 위와 같은 문제를 해결할 수 있습니다.
이번 포스팅에서는 Argo Workflow Standalone DEX를 사용해 Google IdP로 인증을 수행하는 방법에 대해 알아보겠습니다.
2. Architecture
위 다이어그램은 Argo Workflow와 Standalone DEX를 이용해 Google IdP로 인증을 수행하는 아키텍쳐입니다.
Argo Workflow는 Client로써 DEX에게 인증을 전가하고, DEX는 Argo Workflow 대신 Google IdP에게서 인증 토큰을 받아 다시 Argo Workflow에게 전달하는 역할을 합니다.
인증은 아래와 같은 순서로 이루어집니다.
- End User는 Argo Workflow에서 인증 절차를 시작합니다.
- Argo Workflow는 End User를 DEX의 인증 페이지로 Redirect합니다.
- DEX는 User를 Redirect한 주소와 매핑된 Issuer 페이지(accounts.google.com)로 다시 Redirect합니다.
- User는 Redirect된 Issuer 페이지에서 IdP가 제공하는 인증을 수행합니다.
- 인증을 성공하면 DEX는 User의 Identity를 확인합니다.
- DEX는 Callback URL(Argo Workflow)로 인증 토큰을 전송합니다.
- 토큰을 전송받은 Argo Workflow는 해당 토큰을 사용해 User의 Identity를 확인합니다.
3. Components
Argo Workflow의 Standalone DEX 인증에 필요한 Kubernetes Manifest들을 살펴보겠습니다.
본 포스팅에서는 Argo Workflow 설치에 필요한 과정은 생략합니다.
Argo Workflow 설치 방법은 아래 공식 Docs를 참고 바랍니다.
https://argoproj.github.io/argo-workflows/installation/
1. Deployment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dex
name: dex
namespace: argo
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: dex
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: dex
spec:
containers:
- command:
- /usr/local/bin/dex
- serve
- /etc/dex/cfg/config.yaml
image: ghcr.io/dexidp/dex:v2.35.3
imagePullPolicy: IfNotPresent
name: dex
ports:
- containerPort: 5556
name: http
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: dex/healthz
port: 5556
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/dex/cfg
name: config
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: argo-dex
serviceAccountName: argo-dex
terminationGracePeriodSeconds: 30
volumes:
- configMap:
defaultMode: 420
items:
- key: config.yaml
path: config.yaml
name: dex
name: config
|
cs |
Standalone DEX를 설치하기 위한 Deployment manifest입니다.
Deployment를 적용하기 전 적절한 Serviceaccount와 configmap이 필요함에 유의해야 합니다.
위 Manifest에서 중요한 부분만 살펴보도록 하겠습니다.
1
2
3
4
5
6
|
readinessProbe:
failureThreshold: 3
httpGet:
path: dex/healthz
port: 5556
scheme: HTTP
|
cs |
DEX deployment manifest에서 readinessProbe를 정의하는 block입니다.
GKE 환경에서 Ingress를 이용해 DEX pod를 노출할시, GCP LB는 위의 readinessProbe에 정의된 값을 기반으로 Healthcheck를 구성합니다.
Healthcheck가 200 response를 송신하는 적절한 경로로 구성되지 않는다면 pod가 제대로 노출되지 않는 문제가 발생합니다.
따라서 readinessProbe의 Path 값을 DEX의 Healthcheck 경로로 설정해줘야만 합니다.
DEX는 Issuer URL에 "/healthz"가 추가된 Path를 Healthcheck 경로로 사용합니다.
예를 들어 DEX의 Issuer URL을 "https://argoworkflow/dex"로 구성했다면 Healthcheck 경로는 "dex/healthz"가 됩니다.
2. Configmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
apiVersion: v1
data:
nodeEvents: |
enabled: true
sso: |
scopes:
- email
issuer: https://argo.test-for-lswoo.kro.kr/dex
clientId:
name: argo-workflow-sso
key: client-id
clientSecret:
name: argo-workflow-sso
key: client-secret
redirectUrl: https://argo.test-for-lswoo.kro.kr/oauth2/callback
rbac:
enabled: false
kind: ConfigMap
metadata:
name: workflow-controller-configmap
namespace: argo
|
cs |
Argo Workflow에 적용될 Configmap Manifest입니다.
"sso" 어트리뷰트를 통해 Argo workflow가 적용할 SSO(Single Sign On) 관련 기능을 정의할 수 있습니다.
SSO를 사용하기 위해서는 Argo Workflow의 실행 플래그가 auth-mode=sso 상태여야 한다는 점에 유의합니다.
Configmap을 적용하기 전 적절한 Secret이 생성되어 있어야 합니다.
위 Manifest 중요한 부분을 살펴보도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
sso: |
scopes:
- email
issuer: https://argo.test-for-lswoo.kro.kr/dex
clientId:
name: argo-workflow-sso
key: client-id
clientSecret:
name: argo-workflow-sso
key: client-secret
redirectUrl: https://argo.test-for-lswoo.kro.kr/oauth2/callback
rbac:
enabled: false
|
cs |
Argo Workflow Configmap에서 SSO를 정의하는 block입니다.
각 어트리뷰트의 용도는 다음과 같습니다.
1. scopes : IdP에 요청할 scope를 정의합니다. RBAC에 필요한 정보를 가져올 수 있습니다.
2. issuer : Argo Workflow가 OIDC Provider로 사용할 URL입니다. OIDC Provider로 Standalone DEX를 사용할 것이므로 DEX의 Issuer URL을 적습니다.
3. clientId : IdP가 발급한 Client ID 값이 존재하는 Secret과 그 Secret의 Key 값입니다.
4. clientSecret : IdP가 발급한 Client Secret 값이 존재하는 Secret과 그 Secret의 Key 값입니다.
5. redirectUrl : Provider에게 제공할 redirect URL입니다. 이 경우 DEX에게 제공할 Argo Workflow의 Callback URL을 적습니다.
Argo Workflow는 Callback URL로 "/oauth2/callback" 을 사용하므로 Argo Workflow의 Root URL에 "/oauth2/callback" Path가 붙은 값만을 적어야 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
kind: ConfigMap
apiVersion: v1
metadata:
name: dex
namespace: argo
data:
config.yaml: |
issuer: https://argo.test-for-lswoo.kro.kr/dex #Dex URL
storage:
type: kubernetes
config:
inCluster: true
web:
http: 0.0.0.0:5556
logger:
level: "debug"
format: "text"
connectors:
- type: google
id: google
name: Google
config:
clientID: CLIENT_ID
clientSecret: CLIENT_SECRET
redirectURI: https://argo.test-for-lswoo.kro.kr/dex/callback # Argo Workflow redirect URL
oauth2:
skipApprovalScreen: true
staticClients:
- id: CLIENT_ID
redirectURIs:
- 'https://argo.test-for-lswoo.kro.kr/oauth2/callback'
name: 'argo-workflow'
secret: CLIENT_SECRET
|
cs |
Standalone DEX에 적용될 Configmap Manifest입니다.
config.yaml 데이터를 정의하며, DEX는 정의된 config.yaml을 기반으로 설정을 구성합니다.
위 manifest에서 중요한 부분만 보도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
config.yaml: |
issuer: https://argo.test-for-lswoo.kro.kr/dex #Dex URL
storage:
type: kubernetes
config:
inCluster: true
web:
http: 0.0.0.0:5556
logger:
level: "debug"
format: "text"
connectors:
- type: google
id: google
name: Google
config:
clientID: CLIENT_ID
clientSecret: CLIENT_SECRET
redirectURI: https://argo.test-for-lswoo.kro.kr/dex/callback
oauth2:
skipApprovalScreen: true
staticClients:
- id: CLIENT_ID
redirectURIs:
- 'https://argo.test-for-lswoo.kro.kr/oauth2/callback'
name: 'argo-workflow'
secret: CLIENT_SECRET
|
cs |
dex configmap 중 config.yaml을 정의하는 block입니다.
각 어트리뷰트의 용도는 다음과 같습니다.
1. issuer : DEX가 issuer 페이지로 사용할 URL입니다. Argo Workflow는 인증 수행을 위해 DEX의 issuer URL을 바라봐야 합니다.
일반적으로 Root URL에 "/dex"를 붙인 URL을 사용합니다.
2. storage : DEX가 state 파일을 저장하기 위해 사용할 storage type을 정의합니다. 사용 가능한 type은 여기에서 볼 수 있습니다.
kubernetes 타입을 사용할 시 DEX는 "authreuqest" CRD를 이용해 state를 저장합니다.
때문에 DEX가 kubernetes 타입을 사용하기 위해서는 "authrequest" CRD를 create할 수 있는 권한이 존재해야 합니다.
3. connectors : DEX가 IdP에게 제공할 정보를 정의합니다. 사용할 IdP의 명세를 정의하고 인증에 필요한 Client ID와 Client Secret을 적습니다.
redirectURI에는 DEX의 callback URL을 적습니다. 이는 Dex의 Issuer URL에 "/callback"이 붙은 형태여야만 합니다. 자세한 내용은 여기에서 볼 수 있습니다.
4. staticClients : DEX의 Client 정보를 정의합니다. 이 경우 Argo Workflow가 됩니다. Client ID와 Client Secret을 적습니다.
redirectURIs는 Client로 인증 정보를 보낼 URI를 정의합니다. 이 경우 Argo Workflow configmap에서 정의한 redirectURL과 일치해야 합니다.
5. redirectUrl : Provider에게 제공할 redirect URL입니다. 이 경우 DEX에게 제공할 Argo Workflow의 Callback URL을 적습니다.
Argo Workflow는 Callback URL로 "/oauth2/callback" 을 사용하므로 Argo Workflow의 Root URL에 "/oauth2/callback" Path가 붙은 값만을 적어야 합니다.
3. Secret
1
2
3
4
5
6
7 |
apiVersion: v1
kind: Secret
metadata:
name: argo-workflow-sso
stringData:
client-id: CLIENT_ID
client-secret: CLIENT_SECRET |
cs |
Argo workflow가 SSO 설정을 위해 참조할 Secret manifest입니다.
IdP에서 발급받은 Client ID와 Client Secret을 기입합니다.
4. ServiceAccount & Clusterrole & Clusterrolebinding
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: dex
name: argo-dex
namespace: argo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: argo-dex
rules:
- apiGroups: ["dex.coreos.com"]
resources: ["*"]
verbs: ["*"]
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: argo-dex
namespace: argo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: argo-dex
subjects:
- kind: ServiceAccount
name: argo-dex
namespace: argo
|
cs |
DEX deployment가 사용할 Serviceaccount와 이에 적용될 Clusterole, Clusterrolebinding을 정의하는 Manifest입니다.
이 권한을 통해 DEX가 authrequest 오브젝트 생성 등의 행위를 할 수 있게 됩니다.
5. Ingress
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
apiVersion: v1
items:
- apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argo-workflow-argo-workflows-server
namespace: argo
spec:
rules:
- host: argo.test-for-lswoo.kro.kr
http:
paths:
- backend:
service:
name: argo-workflow-argo-workflows-server
port:
number: 2746
path: /
pathType: Prefix
- backend:
service:
name: dex
port:
number: 5556
path: /dex
pathType: Prefix
|
cs |
Argo Workflow와 Standalone DEX를 노출하는 Ingress manifest입니다.
관리의 편의성을 위해 Argo Workflow와 DEX를 같은 도메인에 두고, DEX를 Issuer URL에 등록한 Path로 분기되도록 구성합니다.
4. DEMO
이제 위에서 살펴본 Manifest를 기반으로 구성한 Standalone DEX 인증 수행 DEMO를 보도록 하겠습니다.
Argo Workflow의 Dashboard에서 Single sign-on 섹션의 LOGIN 버튼을 클릭해 인증을 시작할 수 있습니다.
버튼을 클릭하면 지정된 IdP(google)의 인증 페이지로 redirect 됩니다. IdP가 요구하는 정보를 제공해 인증을 진행합니다.
인증에 성공하면 DEX Log에서 로그인 성공과 IdP에서 어떠한 정보를 가져왔는지에 대한 정보를 확인할 수 있습니다.
동시에 DEX는 상태정보를 담은 authrequest CRD를 생성해 위와 같은 정보를 etcd에 저장합니다. 이 정보를 통해 DEX User의 Identity를 정의합니다.
로그인 이후 인증을 시도했던 Argo Workflow Dashboard로 다시 Redirect됩니다. User Info란에서 인증을 수행한 email 정보를 가지고 있는 것을 확인할 수 있습니다.
DEX issuer URL + "/.well-known/openid-configuration" 주소에서 DEX가 제공하는 OIDC 관련 메타데이터를 확인할 수 있습니다.
제공되는 Scope, Issuer URL, endpoint 등의 정보를 볼 수 있습니다.
5. Cautions
1.
Argo Workflow가 DEX에서 인증 정보를 받을 Redirect URL은 "/oauth2/callback"으로 fix되어 있습니다. 그 외에 다른 값을 넣으면 에러가 발생합니다.
DEX가 IdP로부터 인증 정보를 받아올 Redirect URL은 "/callback"으로 fix되어 있습니다. 그 외에 다른 값을 넣으면 에러가 발생합니다.
2.
Argo workflow + Standalone DEX를 구성하기 위해 사용해야 하는 Redirect URL 값은 총 3개가 존재합니다. 모두 Redirect URL 역할을 하기 때문에 때문에 혼동의 여지가 있으므로 각 URL 값의 속성을 모른 채로 값을 적게 되면 에러를 초래할 수 있습니다.
아래와 같은 기준을 통해 각 Redirect URL의 역할과 적어야 할 값을 알 수 있습니다.
- Argo workflow's Redirect URL : Argo Workflow가 DEX에게서 인증 정보를 받아올 Redirect URL입니다. Argo Workflow의 Root URL/oauth2/callback 형태만을 허용합니다.
- DEX connector's Redirect URL : DEX가 IdP로부터 인증 정보를 받아올 Redirect URL입니다. DEX의 Issuer URL/callback 형태만을 허용합니다.
- DEX staticClients's Redirect URL : DEX가 Argo Workflow에게 인증 정보를 보낼 Redirect URL입니다. 1번 Argo workflow's Redirect URL과 동일한 값만을 허용합니다.
아래는 각 Redirect URL 값의 예시입니다.
Argo Workflow Configmap
DEC Configmap
6. 마무리
지금까지 Standalone DEX를 활용하여 Argo Workflow의 SSO 인증을 구현하는 방법에 대해 알아봤습니다.
Standalone DEX는 Argo Workflow만을 사용하고자 하는 상황에서 OIDC 인증을 위해 Argo CD까지 설치하지 않아도 된다는 이점을 제공합니다.
게다가 Standalone DEX를 활용하면 기존의 Argo CD DEX와 연동해야 했던 제약에서 벗어날 수 있기 때문에 자유로운 인증 수행이 가능해집니다.
이 글을 읽는 분들에게 Argo Workflow를 Standalone DEX와 함께 사용하고자 하는 상황에서 많은 도움이 되기를 바랍니다.
'Devops' 카테고리의 다른 글
Kubecost로 Kubernetes 환경의 FinOps를 구현해보자 (0) | 2023.11.29 |
---|---|
Clean Code를 구현하기 위해 Sonarqube로 정적 코드 분석을 해보자 (2) | 2023.10.28 |
Argo 사용해보기 (1) Argo Project로 CI/CD Pipeline을 구성해보자 (0) | 2023.04.29 |
컨테이너 빌드 도구 선택을 위한 특성 및 성능 비교 (Kaniko, Buildah, Buildkit) (5) | 2023.03.26 |
Tekton 사용해보기 (5) Tekton에 Human Approval 기능을 추가해보자 (0) | 2023.03.18 |