이 튜토리얼에서는 Cloud Run에서 호스팅하는 마이크로서비스를 액세스할 수 있도록 워크로드 아이덴티티 제휴를 사용하여 Google Cloud 외부에서 실행되는 워크로드를 인증하는 방법을 설명합니다. 이 튜토리얼은 워크로드 아이덴티티 제휴를 기존 ID 공급업체(IdP)와 통합하려는 관리자를 대상으로 합니다. 워크로드 아이덴티티 제휴를 사용하면 외부 워크로드를 Google Cloud에서 실행되는 워크로드에 연결할 수 있습니다. Cloud Run을 사용하면 컨테이너화된 스테이트리스(Stateless) 마이크로서비스를 실행할 수 있습니다.
이 튜토리얼에서는 Jenkins를 외부 워크로드로, Keycloak을 IdP로 구성하고 Cloud Run 및 워크로드 아이덴티티 제휴를 구성하는 방법을 안내합니다. 이 튜토리얼을 마치면 워크로드 아이덴티티 제휴를 사용하여 OpenID Connect 인증을 통해 Google Cloud 로 Jenkins 애플리케이션을 인증하는 방법을 알게 됩니다.
워크로드 아이덴티티 제휴를 사용하여 외부 워크로드 인증
워크로드 아이덴티티 제휴를 사용하면 정적 서비스 계정 키를 사용하지 않고도 Google Cloud 외부에서 워크로드를 인증할 수 있습니다.Google Cloud 의 서비스를 사용해야 하는 모든 외부 워크로드에서 이 기능을 활용할 수 있습니다.
워크로드 아이덴티티 제휴를 사용하면 IdP를 사용해서Google Cloud에 직접 인증을 수행할 수 있습니다. 인증하려면 OpenID Connect를 사용합니다. Cloud Run은 인증을 위해 IdP의 OpenID Connect 토큰을 허용합니다.
워크로드 아이덴티티 제휴를 사용할 때의 인증 프로세스는 다음과 같습니다.
- 인증(AUTHN) 라이브러리는 IdP에 JSON 웹 토큰(JWT) 요청을 보냅니다.
- IdP는 JSON 웹 토큰(JWT)에 서명합니다. AUTHN 라이브러리는 변수에서 이 데이터를 읽습니다.
- 라이브러리는 서명된 토큰이 포함된 POST 명령어를 보안 토큰 서비스에 전송합니다.
- 보안 토큰 서비스는 워크로드가 트러스트를 빌드하도록 구성한 워크로드 ID 풀 제공업체를 확인하고 사용자 인증 정보의 ID를 검증합니다.
- 보안 토큰 서비스는 제휴 액세스 토큰을 반환합니다.
- 라이브러리는 제휴된 액세스 토큰을 IAM으로 전송합니다.
- IAM은 ID 토큰의 제휴된 액세스 토큰을 교환합니다. 자세한 내용은 OpenID Connect (OIDC) ID 토큰 만들기를 참고하세요.
- 이 라이브러리는 Jenkins에 ID 토큰을 제공합니다.
- Jenkins는 이 토큰을 사용하여 Cloud Run에 인증합니다.
다음 다이어그램에서는 인증 흐름을 보여줍니다.
Jenkins 구성
온프레미스 환경이나 다른 클라우드와 같이Google Cloud 이외의 환경에서 아래 작업을 완료합니다.
OpenID Connect 및 외부 워크로드를 지원하는 ID 공급업체가 이미 있으면 이 단계를 건너뛰고 Cloud 클라이언트 라이브러리 설치로 넘어갈 수 있습니다.
외부 워크로드를 시뮬레이션하려면 Jenkins가 설치된 VM을 사용하면 됩니다. Jenkins를 Docker 이미지로 실행할 수도 있고, 서버에 직접 설치할 수도 있습니다. 다음 단계에서는 서버에 직접 설치하는 방법을 보여줍니다.
- 원하는 VM에서 명령줄을 엽니다.
- 자바를 설치합니다. - $ sudo apt update $ sudo apt install openjdk-11-jre $ java -version
- Jenkins를 설치합니다. - curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \ /usr/share/keyrings/jenkins-keyring.asc > /dev/null echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \ https://pkg.jenkins.io/debian-stable binary/ | sudo tee \ /etc/apt/sources.list.d/jenkins.list > /dev/null sudo apt-get update sudo apt-get install jenkins
- 포트 8080에서 Jenkins 서버에 액세스할 수 있는지 확인합니다. 방화벽 뒤에 있는 VM을 사용하는 경우 적절한 포트가 열려 있는지 확인합니다. 
- 관리자 비밀번호를 확인하고 Jenkins를 설정합니다. 자세한 내용은 설치 후 설정 마법사를 참조하세요. 
- 다음 작업을 완료하여 SSL을 설정합니다. - 도메인 제공업체가 있으면 해당 인증 기관(CA)을 통해 서명된 인증서를 요청할 수 있습니다. 또는 zerossl.com에서 90일 동안 유지되는 무료 서명 인증서를 가져올 수 있습니다.
- 인증서 ZIP 파일을 다운로드하여 Jenkins가 실행 중인 서버로 전송합니다. - scp -i CERTFILE.pem -r CERTFILE.zip VM_FQDN:/home/USERNAME- 다음을 바꿉니다. - CERTFILE을 공개 키가 포함된 인증서 파일의 이름으로 바꿉니다.
- VM_FQDN을 Google Cloud외부의 서버 FQDN으로 바꿉니다.
- USERNAME을 사용자 이름으로 바꿉니다.
 
- 파일 이름을 바꾸고 Jenkins에서 사용할 수 있는 .pkcs12 파일을 생성합니다. - openssl rsa -in KEYFILE.com.key -out KEYFILE.com.key- KEYFILE을 인증서 파일의 이름으로 바꿉니다.
 
- /etc/sysconfig/jenkins파일을 업데이트합니다.- 텍스트 편집기에서 파일을 엽니다. - vi /etc/sysconfig/jenkins
- JENKINS_PORT를- -1로 설정합니다.
- JENKINS_HTTPS_PORT를- 8443으로 설정합니다.
- 파일 하단에 다음 인수를 추가합니다. - JENKINS_ARGS="--httpsCertificate=/var/lib/jenkins/.ssl/CERTFILE.crt --httpsPrivateKeys=/var/lib/jenkins/.ssl/KEYFILE.pkcs1.key"- 다음을 바꿉니다. - CERTFILE을 .crt 형식을 사용하는 인증서 파일 이름으로 바꿉니다.
- KEYFILE을 PKCS 키 파일 이름으로 바꿉니다.
 
 
- Jenkins 서버를 다시 시작합니다. 
- 방화벽에서 포트 8443이 열려 있는지 확인하고 포트 8443에서 Jenkins에 액세스합니다. 
- Keycloak과 Jenkins를 통합하는 데 필요한 Jenkins 플러그인을 설치합니다. 다음 중 하나를 선택할 수 있습니다. - 플러그인을 설치하려면 다음을 수행합니다. - Jenkins 대시보드에서 Manage Jenkins(Jenkins 관리) > Manage Plugins(플러그인 관리)로 이동합니다.
- Available(사용 가능)을 선택하고 원하는 플러그인을 검색합니다. 다음 스크린샷은 플러그인 관리자에서 Available(사용 가능) 탭을 선택한 모습을 보여줍니다.  
- 플러그인을 설치합니다. 
 
Keycloak 구성
이 튜토리얼에서 Keycloak은 사용자, 그룹, 역할을 관리합니다. Keycloak은 렐름을 사용하여 사용자를 관리합니다.
- Google Cloud외부에서 실행 중인 VM에 Keycloak 서버를 설치합니다. 이 튜토리얼의 경우 Docker 컨테이너에서 Keycloak을 설치하는 것이 좋습니다. 
- Keycloak 관리 콘솔을 엽니다. 
- Realm settings(렐름 설정)로 이동합니다. 
- General(일반) 탭에서 필드가 다음과 같이 설정되었는지 확인합니다. - Enabled(사용 설정됨): ON
- User-Managed Access(사용자 관리형 액세스): OFF
- Endpoints(엔드포인트): OpenID Endpoint Configuration 및 SAML 2.0 Identity Provider Metadata
 - 다음 스크린샷에서는 구성해야 하는 필드를 보여줍니다.  
- Keycloak에 사용자 인증을 요청할 수 있는 항목이 필요하므로 클라이언트를 만듭니다. 클라이언트는 Keycloak을 사용하여 싱글 사인온(SSO) 솔루션을 제공하는 애플리케이션과 서비스인 경우가 많습니다. - Keycloak 관리 콘솔에서 Clients(클라이언트) > Create(만들기)를 클릭합니다.
- 다음을 입력합니다. - Client ID(클라이언트 ID): jenkins
- Client Protocol(클라이언트 프로토콜): openid-connect
- Root URL(기준 URL): http://JENKINS_IP_ADDRESS:8080, 여기서 JENKINS_IP_ADDRESS는 Jenkins 서버의 IP 주소입니다.
 - 다음 스크린샷에서는 구성해야 하는 필드를 보여줍니다.  
- 저장을 클릭합니다. 
 
- Installation(설치) 탭에서 토큰 형식이 Keycloak OIDC JSON인지 확인합니다. Jenkins 설정을 완료하는 데 필요하므로 이 토큰의 사본을 만듭니다. 
- 테스트 그룹을 만들려면 다음 안내를 따르세요. - Keycloak 관리 콘솔에서 Groups(그룹) > New(새로 만들기)를 클릭합니다.
- 그룹 이름을 입력하고 Save(저장)를 클릭합니다.
- 테스트 그룹을 하나 더 만듭니다. 그룹에 역할을 할당할 수 있지만 이 튜토리얼에서는 역할이 필요하지 않습니다.
 
- 그룹에 추가할 테스트 사용자를 만들려면 다음 단계를 따르세요. - Keycloak 관리 콘솔에서 Manage user(사용자 관리) > Add users(사용자 추가)를 클릭합니다.
- 사용자 정보를 입력하고 Save(저장)를 클릭합니다. - 다음 스크린샷에서는 사용자 계정 정보 예시를 보여줍니다.  
- Credentials(사용자 인증 정보) 탭을 클릭하고 Temporary(임시)가 Off로 설정되어 있는지 확인합니다. 
- 비밀번호를 재설정합니다. - 나중에 JWT에서 이 계정을 인증에 사용합니다. - 다음 스크린샷은 구성해야 하는 필드가 있는 Credentials(사용자 인증 정보) 탭을 보여줍니다.  
- Groups(그룹) 탭을 클릭하고 이전에 만든 그룹 중 하나를 선택합니다. 
- 참여를 클릭합니다. 
- 이 단계를 반복하여 테스트 사용자를 더 만듭니다. 
 
OpenID Connect 구성을 위해 Jenkins 구성
이 섹션에서는 Jenkins용 OpenID Connect 플러그인을 구성하는 방법을 설명합니다.
- Jenkins 서버에서 Manage Jenkins(Jenkins 관리) > Configure Global Security(전역 보안 구성)로 이동합니다.
- Security Realm(보안 렐름)에서 Keycloak Authentication Plugin(Keycloak 인증 플러그인)을 선택합니다. Save(저장)를 클릭합니다. 
- Configure system(시스템 구성)을 클릭합니다. 
- Global Keycloak(전역 Keycloak) 설정에서 Configure Keycloak(Keycloak 구성)에서 만든 Keycloak 설치 JSON을 복사합니다. JSON 데이터를 다시 가져와야 하는 경우 다음을 완료합니다. - Keycloak 관리 콘솔에서 Clients(클라이언트)로 이동합니다. 
- 클라이언트 이름을 클릭합니다. 
- Installation(설치) 탭에서 Format Option(형식 옵션)을 클릭하고 Keycloak OIDC JSON을 선택합니다. 
 - 다음은 Keycloak JSON의 예시입니다. - { "realm":"master" "auth-server-url":"AUTHSERVERURL" "ssl-required":"none" "resource":"jenkins" "public-client":true "confidential-port":0 }- AUTHSERVERURL은 인증 서버의 URL입니다. 
- OIDC 구성을 저장하려면 Save(저장)를 클릭합니다. 
이제 Jenkins가 Keycloak으로 리디렉션되어 사용자 정보를 가져올 수 있습니다.
Cloud 클라이언트 라이브러리 설치
Keycloak의 JWT를 Google Cloud로 전송하려면 Jenkins 서버에 Cloud 클라이언트 라이브러리를 설치해야 합니다. 이 튜토리얼에서는 Python을 사용하여 SDK로Google Cloud 와 상호작용합니다.
- Jenkins 서버에 Python을 설치합니다. 다음 단계에서는 python3을 설치하는 방법을 보여줍니다. - sudo apt update sudo apt install software-properties-common sudo add-apt-repository ppa:deadsnakes/ppa sudo apt update sudo apt install python3.8
- Cloud 클라이언트 라이브러리를 다운로드하고 가져올 수 있도록 pip3을 설치합니다. - pip3 –version sudo apt update sudo apt install python3-pip pip3 –version
- pip3을 사용하여 Python용 Cloud 클라이언트 라이브러리를 설치합니다. - pip3 install –upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib- 예를 들면 다음과 같습니다. - pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib Collecting google-api-python-client Downloading google_api_python_client-2.42.0-py2.py3-none-any.whl (8.3 MB) USERNAME | 8.3 MB 19.9 MB/s Collecting google-auth-httplib2 Downloading google_auth_httplib2-0.1.0-py2.py3-none-any.whl (9.3 MB) Collecting google-auth-oauthlib Downloading google_auth_oauthlib-0.5.1-py2.py3-non-any.whl (19 KB)- USERNAME을 사용자 이름으로 바꿉니다. 
- Jenkins 서버에 Google Cloud CLI를 설치합니다. 자세한 내용은 빠른 시작: gcloud CLI 설치를 참조하세요. 
Google Cloud 환경 구성
이 섹션에서는 서버리스 컨테이너를 호스팅하는Google Cloud 환경이 Jenkins와 Keycloak을 연결할 수 있도록 완료해야 하는 단계를 설명합니다.
- Google Cloud에서 Cloud Run의 마이크로서비스가 연결된 권한에 액세스할 수 있도록 서비스 계정을 만듭니다. 예를 들어 gcloud CLI를 사용하여 서비스 계정을 만들려면 다음을 수행합니다. - gcloud iam service-accounts create cloudrun-oidc \ –-description="cloud run oidc sa" \ –-display-name="cloudrun-oidc"- 기본적으로는 Cloud Run이 기본 서비스 계정을 자동으로 만듭니다. 하지만 이 계정에는 광범위한 권한 집합이 포함되므로 기본 서비스 계정은 보안상 권장되지 않습니다. 따라서 마이크로서비스용으로 별도의 서비스 계정을 만드는 것이 좋습니다. Cloud Run의 서비스 계정을 만드는 방법은 서비스 계정 만들기 및 관리를 참조하세요. 
- 워크로드 아이덴티티 풀을 만듭니다. gcloud CLI를 사용하여 풀을 만들려면 다음을 실행합니다. - gcloud iam workload-identity-pools create cloudrun-oidc-pool \ --location="global" \ —-description="cloudrun-oidc" \ —-display-name="cloudrun-oidc"
- OpenID Connect용으로 워크로드 아이덴티티 풀 제공업체를 만듭니다. - gcloud iam workload-identity-pools providers create-oidc cloud-run-provider \ --workload-identity-pool="cloudrun-oidc-pool" \ --issuer-uri="VAR_LINK_TO_ENDPOINT" \ --location="global" \ --attribute-mapping ="google.subject=assertion.sub,attribute.isadmin-assertion.isadmin,attribute.aud=assertion.aud" \ --attribute-condition="attribute.isadmin=='true'"- VAR_LINK_TO_ENDPOINT를 Keycloak OIDC 엔드포인트 링크가 포함된 변수로 바꿉니다. 이 링크를 찾으려면 KeyCloud 관리 콘솔의 Realm(렐름) 창에서 General(일반) 탭을 클릭합니다. 엔드포인트는 HTTPS여야 하므로 Keycloak 서버를 HTTPS로 구성해야 합니다.
Keycloak에서 인증된 사용자의 JWT 가져오기
- Keycloak을 실행하는 VM에서 토큰을 텍스트 파일로 다운로드합니다. 예를 들어 Linux에서는 다음을 실행합니다. - curl -L -X POST 'https://IP_FOR_KEYCLOAK:8080/auth/realms/master/protocol/openid-connect/token' -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=jenks' \ --data-urlencode 'grant_type=password' \ --data-urlencode 'client_secret=CLIENT_SECRET \ --data-urlencode 'scope=openid' \ --data-urlencode 'username=USERNAME' \ --data-urlencode 'password=PASSWORD' | grep access_token | cut -c18-1490 > token.txt- 다음을 바꿉니다. - IP_FOR_KEYCLOAK을 Keycloak 서버 IP 주소로 바꿉니다.
- CLIENT_SECRET을 Keycloak 클라이언트 보안 비밀번호로 바꿉니다.
- USERNAME을 Keycloak 사용자로 바꿉니다.
- PASSWORD를 Keycloak 사용자 비밀번호로 바꿉니다.
 - 이 명령어에는 클라이언트 ID, 클라이언트 보안 비밀번호, 사용자 이름, 비밀번호가 포함됩니다. 보안 권장사항에 따라 명령줄을 사용하는 대신 환경 변수를 사용하여 이러한 값을 마스킹하는 것이 좋습니다. 이 예시 명령어는 사용자 인증 정보를 - token.txt라는 파일로 리디렉션합니다.- 원하는 경우 bash 스크립트를 만들어 이 단계를 자동화할 수 있습니다. 
- jwt.io에서 토큰 유효성을 검사합니다. 
- VM에서 사용자 인증 정보 파일을 만듭니다. - gcloud iam workload-identity-pools create-cred-config \ projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/cloudrun-oidc-pool/providers/cloud-run/provider \ --output-file=sts-creds.json \ --credential-source-file=token.txt- 자세한 내용은 gcloud iam workload-identity-pools create-cred-config를 참조하세요. - 출력 파일은 다음과 같아야 합니다. - { "type": "external_account", "audience": "//iam.google.apis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/cloudrun-oidc-pool/subject/USER_EMAIL", "subject_token_type": "urn:ietf:params:oauth:token-type:jwt", "token_url": "https://sts.googleapis.com/v1/token", "credential_source": { "file" "token.txt" } }- PROJECT_NUMBER는 프로젝트 번호입니다.
- VM에서 - sts.creds.json파일을 ADC의 변수로 설정합니다.- export GOOGLE_APPLICATION_CREDENTIALS=/Users/USERNAME/sts-creds.json- USERNAME을 UNIX 사용자 이름으로 바꿉니다. - 워크로드 아이덴티티 제휴가 출시되기 전에 이 값은 서비스 계정 키였습니다. 워크로드 아이덴티티 제휴에서는 이 값이 새로 생성된 사용자 인증 정보 파일입니다. 
- 사용자가 서비스 계정을 가장하도록 역할 결합을 만듭니다. - gcloud iam service-accounts add-iam-policy-binding SERVICE_ACCOUNT \ --role roles/iam.workloadIdentityUser \ --member "principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/cloudrun-oidc-pool/subject/USER_EMAIL- 다음을 바꿉니다. - SERVICE_ACCOUNT를 Google Cloud 환경 구성에서 만든 서비스 계정의 이메일 주소로 바꿉니다. 자세한 내용은 gcloud iam service-accounts add-iam-policy-binding을 참조하세요.
- USER_EMAIL을 이메일 주소로 바꿉니다.
 
- 서비스 계정이 Cloud Run 서비스를 호출하도록 허용합니다. - gcloud run services add-iam-policy-binding SERVICE_NAME --member-"serviceAccount:SERVICE_ACCOUNT" \ --role="roles/run.invoker"- 다음을 바꿉니다. - SERVICE_NAME을 Cloud Run에서 실행되는 마이크로서비스의 이름으로 바꿉니다.
- SERVICE_ACCOUNT를 Cloud Run 서비스 계정의 이메일 주소로 바꿉니다.
 - 자세한 내용은 gcloud run services add-iam-policy-binding을 참조하세요. 
- ID 토큰을 생성합니다. - #!/usr/bin/python from google.auth import credentials from google.cloud import iam_credentials_v1 import google.auth import google.oauth2.credentials from google.auth.transport.requests import AuthorizedSession, Request url = "https://WORKLOAD_FQDN" aud = "https://WORKLOAD_FQDN" service_account = 'SERVICE_ACCOUNT' client = iam_credentials_v1.IAMCredentialsClient() name = "projects/-/serviceAccounts/{}".format(service_account) id_token = client.generate_id_token(name=name,audience=aud, include_email=True) print(id_token.token) creds = google.oauth2.credentials.Credentials(id_token.token) authed_session = AuthorizedSession(creds) r = authed_session.get(url) print(r.status_code) print(r.text)- 다음을 바꿉니다. - WORKLOAD_FQDN을 워크로드 FQDN으로 바꿉니다.
- SERVICE_ACCOUNT를 Cloud Run 서비스 계정의 이메일 주소로 바꿉니다.
 
사용하는 토큰은 Identity and Access Management API를 호출할 수 있으며, 이렇게 하면 Cloud Run 서비스를 호출하는 데 필요한 새 JWT가 제공됩니다.
Jenkins 파이프라인 내에서 토큰을 사용하여 Cloud Run에서 실행 중인 서버리스 컨테이너를 호출할 수 있습니다. 그러나 해당 단계는 이 튜토리얼에서 다루지 않습니다.