Skip to content

Instantly share code, notes, and snippets.

@ruo91
Last active May 22, 2021 01:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ruo91/97c250445e92111711a51f618b3cc9fb to your computer and use it in GitHub Desktop.
Save ruo91/97c250445e92111711a51f618b3cc9fb to your computer and use it in GitHub Desktop.
OpenShift v4.x - Identity Provider 연동

OpenShift v4.x - Identity Provider 연동

OpenShift에서 Identity Provider(a.k.a IDP)를 연동하여, 로그인시 통합인증(Single Sign On)을 구현하는 방법에 대해서 작성한다.

제공하는 Identity Provider가 많지만 현업에서 자주 사용하는 방식은 htpasswd, LDAP, OpenID가 있다.
이 3가지 방식을 기준으로 PoC 환경을 만들고 이를 검증하는 방식으로 진행 한다.

1. HTPasswd 방식

웹 기반의 인증 방식을 구현할때 사용하는 방식 중에 하나이다.
이 인증 방식은 Apache 웹 서버에서 mod_auth_basic 모듈을 사용하여 HTTP 인증 기능(Basic Authentication)을 구현할때,
htpasswd를 사용하여 사용자 계정을 생성하고 파일 기반의 데이터베이스를 사용한다.
(기본적으로 암호화 알고리즘은 MD5를 사용하며, Linux에서는 crypt() 함수를 사용하여 생성한다.)

다음 절차에서는 htpasswd를 사용하여 사용자 생성 및 OpenShift에 IDP를 구성하는 방법에 대해서 설명한다.

1.1. 사용자 생성

사용자 계정을 2개이상 생성 한다.

- htpasswd 옵션

-c: 파일이 없는 경우 새로 생성 한다.
-b: 사용자 계정의 암호를 생성시 사용 된다.

- 작업 디렉토리 생성

[root@bastion ~]# mkdir -p /opt/idp/htpasswd/

- admin 사용자 생성

[root@bastion ~]# htpasswd -cb /opt/idp/htpasswd/file.db admin 'Test!@#'

- ybkim 사용자 생성

[root@bastion ~]# htpasswd -b /opt/idp/htpasswd/file.db ybkim 'Test!@#'

- 사용자 계정 정보 확인

[root@bastion ~]# cat /opt/idp/htpasswd/file.db
admin:$apr1$30oZbRcG$9QqWyT4pVadMSd3RlPh3c.
ybkim:$apr1$K0Wz9TVd$3zs6Xjnf.LLtJDJZrwSWU/

1.2. Secret 생성

htpasswd를 통해 생성한 사용자 계정 정보를 secret로 생성한다.
생성시 계정 정보는 base64 암호화 알고리즘으로 한번 더 암호화 되어 생성 된다.

[root@bastion ~]# oc create secret generic idp-htpasswd-secret \
--from-file=htpasswd=/opt/idp/htpasswd/file.db -n openshift-config

- secret 확인

[root@bastion ~]# oc get secret idp-htpasswd-secret -n openshift-config -o yaml
apiVersion: v1
data:
  htpasswd: YWRtaW46JGFwcjEkZUZzV3dNMjMkLzJta3NSSndma0lHLgjH2m5c8emE66pjdExmgep47BAdKTrsso2Vu8Ke6GEY5W51wwPPMqKZJowXQCead3BhTFQxCg==
kind: Secret
metadata:
  name: idp-htpasswd-secret
  namespace: openshift-config
type: Opaque

1.3. OAuth: HTPasswd 설정

OAuth 설정에 htpasswd 방식의 IDP를 추가 정의하여 반영 한다.

[root@bastion ~]# vi /opt/idp/htpasswd/idp-htpasswd-oauth.yaml
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
  name: cluster
spec:
  identityProviders:
    - name: idp-htpasswd
      type: HTPasswd
      mappingMethod: claim
      htpasswd:
        fileData:
          name: idp-htpasswd-secret

기존 OAuth가 OpenShift에 구성되어 있기 때문에 create가 아닌 replace로 YAML 내용을 반영한다.

[root@bastion ~]# oc replace -f /opt/idp/htpasswd/idp-htpasswd-oauth.yaml

1.4. 웹 콘솔 로그인

위 HTPasswd 방식의 IDP가 반영되기 위해 openshift-authentication namespace의 oauth-openshift Pod가 재배포 된다.
재배포가 정상적으로 수행 되면, Web Console에 접근시 아래와 같이 idp-htpasswd 이름의 로그인 버튼이 생성 된다. OpenShift v4.x - IDP htpasswd: Login

1.5. Role 권한 부여

관리를 위한 admin 계정에 최고 관리자 권한인 cluster-admin Role을 부여를 한다.

1.5.1. 관리자 계정 권한 부여

[root@bastion ~]# oc adm policy add-cluster-role-to-user cluster-admin admin

권한 부여 후 전에는 안보였던 Overview 화면을 볼 수 있게 되었다.
이는, 모든 namespace에 접근 권한을 부여 했기 때문이다. OpenShift v4.x - IDP htpasswd: Overview

1.5.2. 일반 계정 권한 부여

일반 계정은 프로젝트(namespace)를 생성 후 해당 프로젝트에서만 관리 할 수 있도록 admin Role 권한을 부여한다.

[root@bastion ~]# oc new-project ybkim-project
[root@bastion ~]# oc adm policy add-role-to-user admin user1 -n ybkim-project

일반 계정에서는 특정 프로젝트(ybkim-project)에서만 사용이 가능 한 것으로 확인 되었다. OpenShift v4.x - IDP htpasswd: User Project

2. LDAP 방식

LDAP(Lightweight Directory Access Protocol)는 인터넷 기반의 분산 디렉터리 서비스를 제공하는 공개된 표준 프로토콜이다.
LDAP는 DAP(Directory Access Protocol)의 인터넷 프로토콜 통신 부분만 따로 분리해서 경량화로 설계 되었기 때문에,
통신 데이터를 적게 주고 받을수 있는 장점이 있다.

다음 절차에서는 현업에서 많이 사용하는 Microsoft Active Directory(a.k.a MS AD)를 기준으로 작성한다.

- 테스트 환경

OS: Windows Server 2019 Datacenter Edition
SW: Microsoft Active Directory
Domain: ad.ocp4.ybkim.local

2.1. MS Active Directory 구성도

AD의 하위 디렉토리 구조는 아래와 같이 Tree 형태로 구성한다.
본 구성도는 ocp4.ybkim.local 도메인을 사용하는 회사에서 지사별(us, kr)로 구분하여 사용자를 별도 분리 시킨 구성이다.
이는 각각의 지사에서 OpenShift 클러스터가 별도로 존재하고 지사 별로 각기 다른 정책이 있다는 가정하에 설계 되었다. OpenShift v4.x - MS Active Directroy Tree

ADSI 편집기를 통해 확인 한 Tree 구조 OpenShift v4.x - MS Active Directroy Tree2

2.2. Secret 생성

MS Active Directory의 Administrator의 계정 암호를 secret로 생성한다.
생성시 계정 암호는 base64 암호화 알고리즘으로 한번 더 암호화 되어 생성 된다.

[root@bastion ~]# oc create secret generic idp-ms-ad-secret \
--from-literal=bindPassword='Test!@#' -n openshift-config

2.3. OAuth: MS Active Directory 설정

OAuth를 구성하기 위해 YAML 파일을 생성한다.
아래 URL 부분에 있는 baseDN의 범위는 한국지사(kr)로 지정하여 사용자를 조회 할 수 있도록 한다.

[root@bastion ~]# vi /opt/idp/ms-ad/idp-ms-ad-oauth.yaml
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
  name: cluster
spec:
  identityProviders:
    - name: "idp-ms-ad"
      type: LDAP
      mappingMethod: claim
      ldap:
        attributes:
          id:
            - dn
           email:
            - mail
          name:
            - cn
          preferredUsername:
            - uid
        bindDN: >-
          cn=Administrator,cn=Users,dc=ocp4,dc=ybkim,dc=local
        bindPassword:
          name: idp-ms-ad-secret
        insecure: true
        url: >-
          ldap://ad.ocp4.ybkim.local/ou=kr,dc=ocp4,dc=ybkim,dc=local?sAMAccountName

기존 OAuth가 OpenShift에 구성되어 있기 때문에 create가 아닌 replace로 YAML 내용을 반영한다.

[root@bastion ~]# oc replace -f /opt/idp/ms-ad/idp-ms-ad-oauth.yaml

위 YAML에서 주요 부분만 설명한다.

- bindDN
MS Active Directory에서 사용자 계정 조회가 가능한 관리자 계정을 지정한다.

- bindPassword
bindDN의 관리자 계정 암호를 secret key 파일명으로 지정한다.

- insecure
MS Active Directory의 인증서를 사용할지 여부이다.
true는 인증서를 사용하지 않으며, false는 인증서를 사용한다.

- url
LDAP의 사용자를 조회할 기본 디렉토리의 URL을 정의한다.
LDAP의 기본 포트는 389이며, 기본 포트를 변경하여 사용하고 있다면 URL에 해당 포트를 포함 해주면 된다.
ex) ldap://ad.ocp4.ybkim.local:3899/ou=kr,dc=ocp4,dc=ybkim,dc=local?sAMAccountName

사용자 조회 기준값은 sAMAccountName으로 구분한다.

2.4. Web Console 로그인

위 MS AD 방식의 IDP가 반영되기 위해 openshift-authentication namespace의 oauth-openshift Pod가 재배포가 된다.
재배포가 정상적으로 수행 되면, Web Console에 접근시 아래와 같이 idp-ms-ad 이름의 로그인 버튼이 생성 된다. OpenShift v4.x - IDP MS AD: Login

2.5. Role 권한 부여

관리를 위한 kr-admin 계정에 최고 관리자 권한인 cluster-admin Role을 부여를 한다.

2.5.1. 관리자 계정 권한 부여

권한을 주기 앞서 OpenShift의 Web Console로 MS Active Directory IDP로 최초 로그인을 하면, 아래와 같이 FULL NAME과 IDENTITIES에 해당 로그인 내역이 존재하는 것을 확인 가능하다.

[root@bastion ~]# oc get users
NAME                                                                         UID                                    FULL NAME   IDENTITIES
Q049a1GV9Jm2u7rmsCe65wKzPTw5jtS38n2tVEGiREM9b2NwNCxEQz15YmtpbSxEQz1sb2NhbA   5d495790-3bb2-41e9-8696-5b7ca47dce38   kr-admin    idp-ms-ad:Q049a1GV9Jm2u7rmsCe65wKzPTw5jtS38n2tVEGiREM9b2NwNCxEQz15YmtpbSxEQz1sb2NhbA

MS Active Directory에서 Role 권한을 주는 경우 CLI로는 권한을 주기 어렵다.
해서, YAML 파일을 생성하여 Role 권한을 반영 하도록 한다.

위의 고유 NAME 값으로 모든 namepsace에 접근 가능하도록 cluster-admin 권한을 부여 한다.

[root@bastion ~]# vi /opt/idp/ms-ad/idp-ms-ad-cluster-admin-role-binding.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: cluster-admin-kr-admin
subjects:
  - kind: User
    apiGroup: rbac.authorization.k8s.io
    name: Q049a1GV9Jm2u7rmsCe65wKzPTw5jtS38n2tVEGiREM9b2NwNCxEQz15YmtpbSxEQz1sb2NhbA
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
[root@bastion ~]# oc create -f /opt/idp/ms-ad/idp-ms-ad-cluster-admin-role-binding.yaml

권한 부여 후 전에는 안보였던 Overview 화면을 볼 수 있게 되었다.
이는, 모든 namespace에 접근 권한을 부여 했기 때문이다. OpenShift v4.x - IDP MS AD: Overview

2.5.2. 일반 계정 권한 부여

일반 계정은 프로젝트(namespace)를 생성 후 해당 프로젝트에만 관리 할 수 있도록 admin Role 권한을 부여한다.

[root@bastion ~]# oc new-project ad-ybkim-project
[root@bastion ~]# oc get users
NAME                                                                         UID                                    FULL NAME   IDENTITIES
Q049a3IteWJraW0sT1GV9Jm2u7rmsCe65wKzPTw5jtS38n2tVEGiQz15YmtpbSxEQz1sb2NhbA   3c2a41ff-1117-44b1-ab18-b9f419dae3c7   kr-ybkim    idp-ms-ad:Q049a3IteWJraW0sT1GV9Jm2u7rmsCe65wKzPTw5jtS38n2tVEGiQz15YmtpbSxEQz1sb2NhbA

위의 고유 NAME 값으로 ad-ybkim-project의 namepsace에만 접근 가능하도록 admin 권한을 부여 한다.

[root@bastion ~]# vi /opt/idp/ms-ad/idp-ms-ad-admin-role-binding.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: role-admin-kr-ybkim
  namespace: ad-ybkim-project
subjects:
  - kind: User
    apiGroup: rbac.authorization.k8s.io
    name: Q049a3IteWJraW0sT1GV9Jm2u7rmsCe65wKzPTw5jtS38n2tVEGiQz15YmtpbSxEQz1sb2NhbA
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: admin
[root@bastion ~]# oc create -f /opt/idp/ms-ad/idp-ms-ad-admin-role-binding.yaml

일반 계정에서는 특정 프로젝트(ad-ybkim-project)에서만 사용이 가능 한 것으로 확인 되었다. OpenShift v4.x - IDP MS AD: User Project

3. OpenID 방식

OpenID는 사용자 계정을 한번의 로그인으로 여러 서비스를 일일이 가입할 필요 없이,
사용할 수 있도록 해주는 인증 서비스 표준이다.

이 인증방식은 통합인증 시스템(Single Sign On, SSO)이라고 부르며,
포털 사이트나 SNS(Social Networking Service) 같은 곳에서 많이 활용 한다.

이 문서에서는 keycloak을 사용하여 SSO 시스템을 OpenShift의 IDP와 연동하여 구현하도록 한다.

keycloak은 WildFly 기반으로 구성되어 있으며, RedHat에서 개발한 SSO 오픈소스이다.
(상용 제품은 RedHat SSO이고, 기반은 JBoss이다.)

또한, 기본 데이터베이스를 In-Memory 기반의 H2 Database를 사용하며,
Production 레벨의 환경에서는 비권장이고, RDBMS(PostgeSQL, MySQL, MariaDB, Oracle) 등과 같은
Database와 연동하여 사용 할 것을 권장한다.

3.1. Keycloak 구성

3.1.1. 다운로드

https://www.keycloak.org/downloads 접속하여 파일을 다운로드 받는다.

[root@bastion ~]# curl -o '/opt/keycloak-13.0.0.tar.gz' -L 'https://github.com/keycloak/keycloak/releases/download/13.0.0/keycloak-13.0.0.tar.gz'
[root@bastion ~]# tar -xzvf /opt/keycloak-13.0.0.tar.gz -C /opt/
[root@bastion ~]# mv /opt/keycloak-13.0.0 /opt/keycloak

3.1.2. Profile 설정

Keycloak 기본 홈 디렉토리를 설정 한다.

[root@bastion ~]# vi /etc/profile
# Keycloak
export KEYCLOAK_HOME="/opt/keycloak"
export PATH=$PATH:$KEYCLOAK_HOME/bin

3.1.3. SSL 인증서 생성

OpenShift에서 OpenID 기반으로 IDP를 연동하는 경우에는 HTTPS 방식만 지원하기 때문에,
SSL 인증서 기반으로 keycloak 서버를 구동 할 수 있도록 작업이 진행 되어야 한다.

본 작업은 Self Signed 인증서 기반으로 생성부터 OpenShift와 keycloak에 적용까지의 내용을 담고 있다.
실제 Production 환경과는 다를수 있음을 이해 한다.

- 작업 디렉토리 생성

[root@bastion ~]# mkdir -p /opt/idp/certs/{root,router,conf}

- Root CA key 생성

[root@bastion ~]# openssl genrsa -aes256 -out /opt/idp/certs/root/rootca.key -passout pass:'Test!@#' 2048

- OpenSSL 설정 파일 생성

[root@bastion ~]# vi /opt/idp/certs/conf/openssl-rootca.conf
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = req_distinguished_name
req_extensions = req_ext
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol = TLSv1.2

[req_distinguished_name]
countryName = "KR"
stateOrProvinceName = "Seoul"
localityName = "Gangnam-gu"
organizationalUnitName = "OpenShift"
commonName = "OpenShift - Self Signed RootCA"

[req_ext]
basicConstraints = critical,CA:TRUE
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth

- Certificate Signing Request 생성

[root@bastion ~]# openssl req -new \
-key /opt/idp/certs/root/rootca.key \
-out /opt/idp/certs/root/rootca.csr \
-passin pass:'Test!@#' \
-config /opt/idp/certs/conf/openssl-rootca.conf

- Self Signed RootCA 생성

[root@bastion ~]# openssl x509 -req -sha256 -days 36500 -extensions req_ext -set_serial 1 \
-in /opt/idp/certs/root/rootca.csr \
-signkey  /opt/idp/certs/root/rootca.key \
-out  /opt/idp/certs/root/rootca.crt \
-extfile /opt/idp/certs/conf/openssl-rootca.conf \
-passin pass:'Test!@#'

- RootCA 인증서를 Trust Store로 가져오기

[root@bastion ~]# keytool -import -file /opt/idp/certs/root/rootca.crt -keystore /opt/idp/certs/root/rootca.truststore -keypass 'Test!@#' -storepass 'Test!@#'
Owner: CN=Self Signed Root CA, OU=OpenShift, L=Gangnam-gu, ST=Seoul, C=KR
Issuer: CN=Self Signed Root CA, OU=OpenShift, L=Gangnam-gu, ST=Seoul, C=KR
Serial number: 1
Valid from: Fri May 21 17:57:21 KST 2021 until: Sun Apr 27 17:57:21 KST 2121
Certificate fingerprints:
         SHA1: 97:1B:24:A7:43:FC:87:B5:F2:0E:23:75:E1:43:93:6D:D9:B9:FD:3C
         SHA256: E0:B7:BE:23:C0:79:A1:01:44:F3:D7:5A:A6:CE:24:CB:82:DA:1E:6F:99:6C:32:8A:F8:F6:64:B0:AB:4D:A8:C5
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key (3)
Version: {10}

Extensions:

#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen:2147483647
]

#2: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  serverAuth
]

#3: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  DigitalSignature
  Key_Encipherment
]

Trust this certificate? [no]:  yes
Certificate was added to keystore

- Client 인증서

- RSA key pair 생성

[root@bastion ~]# openssl genrsa -aes256 -out /opt/idp/certs/router/router.key -passout pass:'Test!@#' 2048;

- 인증서 암호 삭제

[root@bastion ~]#cp /opt/idp/certs/router/router.key /opt/idp/certs/router/router.enc
[root@bastion ~]#openssl rsa -in /opt/idp/certs/router/router.enc -out /opt/idp/certs/router/router.key -passin pass:'Test!@#';

- OpenSSL 설정파일 생성

[root@bastion ~]# vi /opt/idp/certs/conf/openssl-router.conf
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = req_distinguished_name
req_extensions = req_ext
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol = TLSv1.2

[req_distinguished_name]
countryName = "KR"
stateOrProvinceName = "Seoul"
localityName = "Gangnam-gu"
organizationalUnitName = "OpenShift"
commonName = "*.apps.ocp4.ybkim.local"

[req_ext]
basicConstraints = critical,CA:FALSE
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = "*.apps.ocp4.ybkim.local"

- Certificate Signing Request 생성

[root@bastion ~]# openssl req -new \
-key /opt/idp/certs/router/router.key \
-out /opt/idp/certs/router/router.csr \
-passin pass:'Test!@#' \
-config /opt/idp/certs/conf/openssl-router.conf

- SSL 인증서 생성

[root@bastion ~]# openssl x509 -req -days 36500 \
-in /opt/idp/certs/router/router.csr \
-CA /opt/idp/certs/root/rootca.crt \
-CAkey /opt/idp/certs/root/rootca.key \
-CAcreateserial -out /opt/idp/certs/router/router.crt \
-extensions req_ext \
-passin pass:'Test!@#' \
-extfile /opt/idp/certs/conf/openssl-router.conf

- pkcs12 format 형식으로 변경

router 인증서를 pkcs12 포맷 형태로 변환 한다.

[root@bastion ~]# openssl pkcs12 -export \
-in /opt/idp/certs/router/router.crt \
-inkey /opt/idp/certs/router/router.key \
-out /opt/idp/certs/router/router.p12 \
-name router-keystore \
-password pass:'Test!@#' \
-CAfile /opt/idp/certs/root/rootca.crt

- Java keystore 생성

[root@bastion ~]# keytool -importkeystore \
-deststorepass 'Test!@#' \
-destkeypass 'Test!@#' \
-destkeystore /opt/idp/certs/router/router.keystore \
-srckeystore /opt/idp/certs/router/router.p12 \
-srcstoretype pkcs12 \
-srcstorepass 'Test!@#'

- truststore, keystore 복사

keycloak에서 사용 될 keystore 인증서 파일을 복사한다.

[root@bastion ~]# cp /opt/idp/certs/root/rootca.truststore $KEYCLOAK_HOME/standalone/configuration/
[root@bastion ~]# cp /opt/idp/certs/router/router.keystore $KEYCLOAK_HOME/standalone/configuration/

3.1.4. Keycloak: Bind Address 설정

keycloack 구동시 모든 인터페이스에 서버가 바인딩 될 수 있도록 설정 한다.

[root@bastion ~]# sed -i 's/127.0.0.1/0.0.0.0/g' $KEYCLOAK_HOME/standalone/configuration/standalone.xml

3.1.5. Keycloak: SSL 설정

security-realm 부분의 ApplicationRealm을 아래와 같이 keystore, truststore 부분을 추가/수정한다.

[root@bastion ~]# vi $KEYCLOAK_HOME/standalone/configuration/standalone.xml
    <management>
        <security-realms>
            <security-realm name="ApplicationRealm">
                <server-identities>
                    <ssl>
                        <!--
                        <keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/>
                        -->
                        <!-- Router Keystore -->
                        <keystore path="router.keystore" relative-to="jboss.server.config.dir" keystore-password="Test!@#" alias="router-keystore" key-password="Test!@#"/>
                    </ssl>
                </server-identities>
                <authentication>
                    <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
                    <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
                </authentication>
                <authorization>
                    <properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
                </authorization>
                <!-- RootCA Truststore -->
                <authentication>
                    <truststore path="rootca.truststore" relative-to="jboss.server.config.dir" keystore-password="Test!@#" />
                </authentication>
            </security-realm>
        </security-realms>
        ..........
        ..................
        <subsystem xmlns="urn:jboss:domain:undertow:12.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.sta$
            <buffer-cache name="default"/>
            <server name="default-server">
                <!-- <https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true""/> -->
                <!-- Add verify-client -->
                <https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true" verify-client="REQUESTED"/>
        </subsystem>

3.1.6. Keycloak: 관리자 계정 생성

처음 구동시 관리자 계정이 없기 때문에, admin 계정을 하나 추가 한다.

[root@bastion ~]# add-user-keycloak.sh --user admin --password 'Test!@#'
Added 'admin' to '/opt/keycloak/standalone/configuration/keycloak-add-user.json', restart server to load user

3.1.7. Keycloak: 서버 구동

background 방식으로 스크립트를 실행하여 서버를 구동한다.

[root@bastion ~]# /opt/keycloak/bin/standalone.sh > /dev/null 2>&1 &

3.1.8. OS: 방화벽 오픈

keycloack의 기본 포트는 HTTP(TCP/8080), HTTPS(TCP/8443)이므로 OS단의 방화벽에서 해당 포트를 오픈 해준다.

[root@bastion ~]# firewall-cmd --permanent --zone=public --add-port=8080/tcp
[root@bastion ~]# firewall-cmd --permanent --zone=public --add-port=8443/tcp
[root@bastion ~]# firewall-cmd --reload

3.1.9. Keycloack: Realm 추가

Keycloak의 Web Console에 로그인 후 Realm을 추가 한다.

Administration Console을 누른 후 admin / Test!@# 관리자 사용자 계정을 통해 로그인 한다. OpenShift v4.x - IDP Keycloak: Administration Console

Master Realm에서 "Add realm"을 추가 한다. OpenShift v4.x - IDP Keycloak: Add Realm #1

추가할 Realm의 이름을 "openshift"로 입력 한다. OpenShift v4.x - IDP Keycloak: Add Realm #2

3.1.10. Keycloack: Realm ClientID 추가

추가 된 Realm인 "openshift"에서 좌측 "Client"를 누른 후 우측 "Create"를 눌러 생성 한다. OpenShift v4.x - IDP Keycloak: Create ClientID #1

새로 생성할 "ClientID"의 이름을 "sso"라 입력 한다. OpenShift v4.x - IDP Keycloak:Create ClientID #2

새로 생성한 ClientID인 "sso"에서 Access Type을 "confidential"로 선택 한다.
Vaild Redirect URIs는 OpenShift의 OAuth 주소를 적는다.
ex) https://oauth-openshift.apps.ocp4.ybkim.local/* OpenShift v4.x - IDP Keycloak: Access Type - confidential

이후 Credentials 메뉴에서 Secret key를 기억 한다. OpenShift v4.x - IDP Keycloak: Credentials - Secret

3.1.11. Keycloack: User 추가

좌측 하단 부분에 위치하는 "Users"를 선택하여 우측 "Add user"를 선택 한다. OpenShift v4.x - IDP Keycloak: Add Users

sso-admin 이라는 사용자 계정을 추가한다. OpenShift v4.x - IDP Keycloak: Add Account of sso-admin #1

이후 Credentials 메뉴에서 Password를 지정한다.
Temporay는 기본값으로 활성화 되어 있으며, 이는 임시 Password로 설정되고 최초 로그인시 Password를 변경할 수 있도록 한다.
Temporay를 비활성화(OFF)를 하는 경우 Password 변경 없이 현재 지정한 Password로 사용할 수 있다. OpenShift v4.x - IDP Keycloak: Add Account of sso-admin #2

Password를 입력하고 "Set Password" 버튼을 누르면 최종 설정 된다. OpenShift v4.x - IDP Keycloak: Add Account of sso-admin #3

같은 방법으로 sso-ybkim 이라는 사용자 계정을 추가한다. OpenShift v4.x - IDP Keycloak: Add Account of sso-ybkim #1 OpenShift v4.x - IDP Keycloak: Add Account of sso-ybkim #2

사용자 추가 이후 "View all users"를 누르면 위에 추가 한 사용자 목록을 확인 할 수 있다. OpenShift v4.x - IDP Keycloak: View all users

3.2. Ingress(Router) 인증서 설정

Router Pod의 기본 인증서는 ingress-operator가 2년이 되기 전에 인증서를 재갱신 한다.
이렇게 되면, 매 2년마다 서비스 장애가 발생 되는 원인이며, 이를 방지 하고자 Self Signed 인증서를 반영한다.

또한, keycloak에서 사용하는 keystore 인증서는 Self Signed 인증서를 기반으로 만들어졌기 때문에,
OpenShift에서 *.apps.ocp4.ybkim.local 도메인에 포함 된 keycloak 인증서를 자동 trust 하도록 한다.

- Router 인증서 복사

위에서 생성한 router.crt, router.key 인증서를 tls.crt, tls.key 이름으로 복사 한다.

[root@bastion ~]# cd /opt/idp/certs/router/
[root@bastion router]# cp router.crt tls.crt
[root@bastion router]# cp router.key tls.key

- Router 인증서 Secret 등록

인증서를 tls.crt, tls.key 이름으로 secret 저장소에 생성한다.

[root@bastion router]# oc create secret tls router-100y-cert --cert=tls.crt --key=tls.key -n openshift-ingress

- Trust CA 인증서 추가

Router 인증서를 신뢰하는 인증서로 등록 하도록 ca-bundle.crt에 인증서를 추가 등록 한다.

[root@bastion router]# oc create configmap router-100y-cert --from-file=ca-bundle.crt=tls.crt -n openshift-config

- 기본 서비스 인증서 적용

추가 한 Router 인증서를 모든 서비스에 사용 하도록 설정 한다.

[root@bastion router]# oc patch proxy/cluster \
--patch='{"spec":{"trustedCA":{"name":"router-100y-cert"}}}' --type=merge

- Ingress Operator 설정

Router 인증서를 실제로 Router Pod에 마운트하여 사용하기 위한 작업을 진행 한다.

[root@bastion router]# oc patch ingresscontroller/default \
--patch '{"spec":{"defaultCertificate":{"name":"router-100y-cert"}}}' \
--type=merge -n openshift-ingress-operator

인증서가 반영 되기까지 시간이 꽤 많이 소요 되므로 정상화 될때까지 기다린다.

3.3. Secret 생성

Keycloak ClientID의 Credentials Secret Key를 Secret로 생성한다.
생성시 Secret key는 base64 암호화 알고리즘으로 한번 더 암호화 되어 생성 된다.

[root@bastion ~]# oc create secret generic idp-openid-secret \
--from-literal=clientSecret='d65adf01-cb7e-40b0-b159-c47af185e51f' -n openshift-config

3.4. OAuth: OpenID 설정

OpenID 기반의 YAML 파일을 생성한다.

[root@bastion ~]# vi /opt/idp/openid/idp-openid-oauth.yaml
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
  name: cluster
spec:
  identityProviders:
    - name: idp-openid
      type: OpenID
      mappingMethod: claim
      openID:
        claims:
          email:
            - email
          name:
            - name
          preferredUsername:
            - preferred_username
        clientID: sso
        clientSecret:
          name: idp-openid-secret
        extraScopes: []
        issuer: 'https://keylocak.apps.ocp4.ybkim.local:8443/auth/realms/openshift'

위 YAML에서 주요 부분만 설명한다.

- clientID
Keycloak에서 생성한 Realm의 ClientID를 입력한다.

- clientSecret
Keycloak에서 생성한 Realm의 ClientID의 Secret key이다.
OpenShift에서 secret key로 업로드한 이름으로 입력한다.

- issuer
Keycloak에서 생성한 Realm의 이름이며,
OpenID로 로그인 행위시 Token 값을 얻기 위한 주소이다.

기존 OAuth가 OpenShift에 구성되어 있기 때문에 create가 아닌 replace로 YAML 내용을 반영한다.

[root@bastion ~]# oc replace -f /opt/idp/openid/idp-openid-oauth.yaml

3.4. 웹 콘솔 로그인

위 OpenID 방식의 IDP가 반영되기 위해 openshift-authentication namespace의 oauth-openshift Pod가 재배포 된다.
재배포가 정상적으로 수행 되면, Web Console에 접근시 아래와 같이 idp-openid 이름의 로그인 버튼이 생성 된다. OpenShift v4.x - IDP OpenID: Login

로그인 화면이 keycloak 화면으로 redirect 되는 것을 확인 가능하다.
keycloak에서 생성한 sso-admin 계정으로 접근 해본다. OpenShift v4.x - IDP OpenID: Keyloak Redirect

3.5. Role 권한 부여

관리를 위한 sso-admin 계정에 최고 관리자 권한인 cluster-admin Role을 부여를 한다.

3.5.1. 관리자 계정 권한 부여

[root@bastion ~]# oc adm policy add-cluster-role-to-user cluster-admin sso-admin

권한 부여 후 전에는 안보였던 Overview 화면을 볼 수 있게 되었다.
이는, 모든 namespace에 접근 권한을 부여 했기 때문이다. OpenShift v4.x - IDP OpenID: Overview

3.5.2. 관리자 계정 권한 부여

일반 계정은 프로젝트(namespace)를 생성 후 해당 프로젝트에서만 관리 할 수 있도록 admin Role 권한을 부여한다.

[root@bastion ~]# oc new-project sso-ybkim-project
[root@bastion ~]# oc adm policy add-role-to-user admin sso-ybkim -n sso-ybkim-project

일반 계정에서는 특정 프로젝트(sso-ybkim-project)에서만 사용이 가능 한 것으로 확인 되었다. OpenShift v4.x - IDP OpenID: User Project

4. Identity Provider 초기화

모든 설정을 초기화 하고 싶을 경우 아래와 같은 방법으로 IDP를 초기화 할 수 있다.

- IDP 초기화 YAML 생성

[root@bastion ~]# vi /opt/idp/idp-init.yaml
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
  name: cluster
spec: {}

- IDP 초기화

[root@bastion ~]# oc replace -f /opt/idp/idp-init.yaml

5. RefURL

[1]: Apache Docs - Authentication and Authorization
[2]: Apache Docs - htpasswd - Manage user files for basic authentication
[3]: OpenShift Docs - Sample LDAP Custom Resource
[4]: OpenShift Blog - Adding authentication to your Kubernetes Web applications with Keycloak
[5]: Keycloak Docs - Keycloak on Openshift
[6]: YouTube - Steve Konish: OpenShift 4.5 with Red Hat Single-Sign-On (SSO) 7.3
[7]: GitHub Gist - gyfoster: Instructions for enabling mutual SSL in Keycloak and WildFly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment