Cloud Run 및 워크로드 아이덴티티 제휴 통합


이 튜토리얼에서는 워크로드 아이덴티티 제휴를 사용하여 Google Cloud 외부에서 실행되는 워크로드를 인증하여 Cloud Run에서 호스팅하는 마이크로서비스에 액세스할 수 있도록 하는 방법을 설명합니다. 이 튜토리얼은 워크로드 아이덴티티 제휴를 기존 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 토큰을 허용합니다.

워크로드 아이덴티티 제휴를 사용할 때의 인증 프로세스는 다음과 같습니다.

  1. 인증(AUTHN) 라이브러리는 IdP에 JSON 웹 토큰(JWT) 요청을 보냅니다.
  2. IdP는 JSON 웹 토큰(JWT)에 서명합니다. AUTHN 라이브러리는 변수에서 이 데이터를 읽습니다.
  3. 라이브러리는 보안 토큰 서비스에 서명된 토큰을 포함하는 POST 명령어를 전송합니다.
  4. 보안 토큰 서비스는 워크로드가 트러스트를 빌드하도록 구성한 워크로드 ID 풀 제공업체를 확인하고 사용자 인증 정보의 ID를 검증합니다.
  5. 보안 토큰 서비스는 제휴 토큰을 반환합니다.
  6. 라이브러리는 IAM에 토큰을 전송합니다.
  7. IAM은 이 토큰을 서비스 계정의 OpenID Connect 토큰과 교환합니다. 자세한 내용은 OpenID Connect ID 토큰 생성을 참조하세요.
  8. 라이브러리는 Jenkins에 OpenID Connect 토큰을 제공합니다.
  9. Jenkins는 이 토큰을 사용하여 Cloud Run에 인증합니다.

다음 다이어그램은 인증 흐름을 보여줍니다.

인증 흐름

목표

  • Jenkins를 외부 워크로드로 구성합니다.
  • Keycloak을 OpenID Connect와 호환되는 IdP로 구성합니다.
  • Jenkins를 Keycloak과 연결합니다.
  • Cloud 클라이언트 라이브러리를 설치하여 Keycloak에서 Google Cloud로 JWT 토큰을 가져옵니다.
  • Google Cloud를 Keycloak 및 Jenkins에 연결합니다.
  • Keycloak에서 인증된 사용자의 JWT를 가져옵니다.

이 튜토리얼에서는 Keycloak을 사용하지만 GitLab, Okta, OneLogin과 같이 OpenID Connect를 지원하는 모든 ID 공급업체를 사용할 수 있습니다.

비용

이 문서에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

이 문서에 설명된 태스크를 완료했으면 만든 리소스를 삭제하여 청구가 계속되는 것을 방지할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

  1. In the Google Cloud console, go to the project selector page.

    Go to project selector

  2. Select or create a Google Cloud project.

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Cloud Run에서 마이크로서비스를 설정합니다. 자세한 내용은 빠른 시작: Cloud Run에 컨테이너 배포를 참조하세요.

Jenkins 구성

온프레미스 환경이나 다른 클라우드와 같이 Google Cloud 이외의 환경에서 아래 작업을 완료합니다.

OpenID Connect 및 외부 워크로드를 지원하는 ID 공급업체가 이미 있으면 이 단계를 건너뛰고 Cloud 클라이언트 라이브러리 설치로 넘어갈 수 있습니다.

외부 워크로드를 시뮬레이션하려면 Jenkins가 설치된 VM을 사용하면 됩니다. Jenkins를 Docker 이미지로 실행할 수도 있고, 서버에 직접 설치할 수도 있습니다. 다음 단계에서는 서버에 직접 설치하는 방법을 보여줍니다.

  1. 원하는 VM에서 명령줄을 엽니다.
  2. 자바를 설치합니다.

    $ sudo apt update
    $ sudo apt install openjdk-11-jre
    $ java -version
    
  3. Jenkins를 설치합니다.

    curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io.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
    
  4. 포트 8080에서 Jenkins 서버에 액세스할 수 있는지 확인합니다. 방화벽 뒤에 있는 VM을 사용하는 경우 적절한 포트가 열려 있는지 확인합니다.

  5. 관리자 비밀번호를 확인하고 Jenkins를 설정합니다. 자세한 내용은 설치 후 설정 마법사를 참조하세요.

  6. 다음 작업을 완료하여 SSL을 설정합니다.

    1. 도메인 제공업체가 있으면 해당 인증 기관(CA)을 통해 서명된 인증서를 요청할 수 있습니다. 또는 zerossl.com에서 90일 동안 유지되는 무료 서명 인증서를 가져올 수 있습니다.
    2. 인증서 zip 파일을 다운로드하고 Jenkins를 실행하는 서버로 전송합니다.

      scp -i CERTFILE.pem -r CERTFILE.zip VM_FQDN:/home/USERNAME
      

      다음을 바꿉니다.

      • CERTFILE을 공개 키가 포함된 인증서 파일의 이름으로 바꿉니다.
      • VM_FQDN을 Google Cloud 외부의 서버 FQDN으로 바꿉니다.
      • USERNAME을 사용자 이름으로 바꿉니다.
    3. 파일 이름을 바꾸고 Jenkins에서 사용할 수 있는 .pkcs12 파일을 생성합니다.

      openssl rsa -in KEYFILE.com.key -out KEYFILE.com.key

      KEYFILE을 인증서 파일의 이름으로 바꿉니다.

  7. /etc/sysconfig/jenkins 파일을 업데이트합니다.

    1. 텍스트 편집기에서 파일을 엽니다.

      vi /etc/sysconfig/jenkins
      
    2. JENKINS_PORT-1로 설정합니다.

    3. JENKINS_HTTPS_PORT8443으로 설정합니다.

    4. 파일 하단에 다음 인수를 추가합니다.

      JENKINS_ARGS="--httpsCertificate=/var/lib/jenkins/.ssl/CERTFILE.crt --httpsPrivateKeys=/var/lib/jenkins/.ssl/KEYFILE.pkcs1.key"

      다음을 바꿉니다.

      • CERTFILE을 .crt 형식을 사용하는 인증서 파일 이름으로 바꿉니다.
      • KEYFILE을 PKCS 키의 파일 이름으로 바꿉니다.
  8. Jenkins 서버를 다시 시작합니다.

  9. 방화벽에서 포트 8443이 열려 있는지 확인하고 포트 8443에서 Jenkins에 액세스합니다.

  10. Keycloak과 Jenkins를 통합하는 데 필요한 Jenkins 플러그인을 설치합니다. 다음 중 하나를 선택할 수 있습니다.

    플러그인을 설치하려면 다음을 수행합니다.

    1. Jenkins 대시보드에서 Manage Jenkins(Jenkins 관리) > Manage Plugins(플러그인 관리)로 이동합니다.
    2. Available(사용 가능)을 선택하고 원하는 플러그인을 검색합니다. 다음 스크린샷은 플러그인 관리자에서 Available(사용 가능) 탭을 선택한 모습을 보여줍니다.

      Jenkins 플러그인 관리자

    3. 플러그인을 설치합니다.

Keycloak 구성

이 튜토리얼에서 Keycloak은 사용자, 그룹, 역할을 관리합니다. Keycloak은 렐름을 사용하여 사용자를 관리합니다.

  1. Google Cloud 외부에서 실행되는 VM에 Keycloak 서버를 설치합니다. 이 튜토리얼에서는 Docker 컨테이너에서 Keycloak을 설치하는 것이 좋습니다.

  2. Keycloak 관리 콘솔을 엽니다.

  3. Realm settings(렐름 설정)로 이동합니다.

  4. General(일반) 탭에서 필드가 다음과 같이 설정되었는지 확인합니다.

    • Enabled(사용 설정됨): ON
    • User-Managed Access(사용자 관리형 액세스): OFF
    • Endpoints(엔드포인트): OpenID Endpoint ConfigurationSAML 2.0 Identity Provider Metadata

    다음 스크린샷은 구성해야 하는 필드를 보여줍니다.

    Keycloak 일반 설정

  5. Keycloak에 사용자 인증을 요청할 수 있는 주체가 필요하므로 클라이언트를 만듭니다. 클라이언트는 Keycloak을 사용하여 싱글 사인온(SSO) 솔루션을 제공하는 애플리케이션과 서비스인 경우가 많습니다.

    1. Keycloak 관리 콘솔에서 Clients(클라이언트) > Create(만들기)를 클릭합니다.
    2. 다음을 입력합니다.

      • Client ID(클라이언트 ID): jenkins
      • Client Protocol(클라이언트 프로토콜): openid-connect
      • Root URL(루트 URL): http://JENKINS_IP_ADDRESS:8080, 여기서 JENKINS_IP_ADDRESS는 Jenkins 서버의 IP 주소입니다.

      다음 스크린샷은 구성해야 하는 필드를 보여줍니다.

      Keycloak 클라이언트 추가

    3. Save(저장)를 클릭합니다.

  6. Installation(설치) 탭에서 토큰 형식이 Keycloak OIDC JSON인지 확인합니다. Jenkins 설정을 완료하는 데 필요하므로 이 토큰의 사본을 만듭니다.

  7. 테스트 그룹을 만들려면 다음 안내를 따르세요.

    1. Keycloak 관리 콘솔에서 Groups(그룹) > New(새로 만들기)를 클릭합니다.
    2. 그룹 이름을 입력하고 Save(저장)를 클릭합니다.
    3. 테스트 그룹을 하나 더 만듭니다. 그룹에 역할을 할당할 수 있지만 이 튜토리얼에서는 역할이 필요하지 않습니다.
  8. 그룹에 추가할 테스트 사용자를 만들려면 다음 단계를 따르세요.

    1. Keycloak 관리 콘솔에서 Manage user(사용자 관리) > Add users(사용자 추가)를 클릭합니다.
    2. 사용자 정보를 입력하고 Save(저장)를 클릭합니다.

      다음 스크린샷은 사용자 계정의 예시 정보를 보여줍니다.

      Keycloak 사용자 추가

    3. Credentials(사용자 인증 정보) 탭을 클릭하고 Temporary(임시)Off로 설정되어 있는지 확인합니다.

    4. 비밀번호를 재설정합니다.

      나중에 JWT에서 이 계정을 인증에 사용합니다.

      다음 스크린샷은 구성해야 하는 필드가 있는 Credentials(사용자 인증 정보) 탭을 보여줍니다.

      Keycloak 비밀번호 변경

    5. Groups(그룹) 탭을 클릭하고 이전에 만든 그룹 중 하나를 선택합니다.

    6. Join(참여)을 클릭합니다.

    7. 이 단계를 반복하여 테스트 사용자를 더 만듭니다.

OpenID Connect 구성을 위한 Jenkins 구성

이 섹션에서는 Jenkins용 OpenID Connect 플러그인을 구성하는 방법을 설명합니다.

  1. Jenkins 서버에서 Manage Jenkins(Jenkins 관리) > Configure Global Security(전역 보안 구성)로 이동합니다.
  2. Security Realm(보안 렐름)에서 Keycloak Authentication Plugin(Keycloak 인증 플러그인)을 선택합니다. Save(저장)를 클릭합니다.

  3. Configure system(시스템 구성)을 클릭합니다.

  4. Global Keycloak(전역 Keycloak) 설정에서 Configure Keycloak(Keycloak 구성)에서 만든 Keycloak 설치 JSON을 복사합니다. JSON 데이터를 다시 가져와야 하는 경우 다음을 완료하세요.

    1. Keycloak 관리 콘솔에서 Clients(클라이언트)로 이동합니다.

    2. 클라이언트 이름을 클릭합니다.

    3. 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입니다.

  5. OIDC 구성을 저장하려면 Save(저장)를 클릭합니다.

이제 Jenkins가 Keycloak로 리디렉션하여 사용자 정보를 가져올 수 있습니다.

Cloud 클라이언트 라이브러리 설치

Keycloak에서 Google Cloud로 JWT를 전송하려면 Jenkins 서버에 Cloud 클라이언트 라이브러리를 설치해야 합니다. 이 튜토리얼에서는 Python을 사용하여 SDK로 Google Cloud와 상호작용합니다.

  1. 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
    
  2. Cloud 클라이언트 라이브러리를 다운로드하고 가져올 수 있도록 pip3을 설치합니다.

    pip3 –version
    sudo apt update
    sudo apt install python3-pip
    pip3 –version
    
  3. 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을 사용자 이름으로 바꿉니다.

  4. Jenkins 서버에 Google Cloud CLI를 설치합니다. 자세한 내용은 빠른 시작: gcloud CLI 설치를 참조하세요.

Google Cloud 환경 구성

이 섹션에서는 서버리스 컨테이너를 호스팅하는 Google Cloud 환경이 Jenkins와 Keycloak을 연결할 수 있도록 완료해야 하는 단계를 설명합니다.

  1. 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용 서비스 계정을 만드는 방법은 서비스 계정 만들기 및 관리를 참조하세요.

  2. 워크로드 아이덴티티 풀을 만듭니다. gcloud CLI를 사용하여 풀을 만들려면 다음을 실행하세요.

    gcloud iam workload-identity-pools create cloudrun-oidc-pool \
      --location="global" \
      —-description="cloudrun-oidc" \
      —-display-name="cloudrun-oidc"
    
  3. 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 가져오기

  1. 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 스크립트를 만들어 이 단계를 자동화할 수 있습니다.

  2. jwt.io에서 토큰을 검증합니다.

  3. 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는 프로젝트 번호입니다.

  4. VM에서 sts.creds.json 파일을 ADC의 변수로 설정합니다.

    export GOOGLE_APPLICATION_CREDENTIALS=/Users/USERNAME/sts-creds.json
    

    USERNAME을 UNIX 사용자 이름으로 바꿉니다.

    워크로드 아이덴티티 제휴가 출시되기 전에는 이 값이 서비스 계정 키였습니다. 워크로드 아이덴티티 제휴에서는 이 값이 새로 생성된 사용자 인증 정보 파일입니다.

  5. 사용자가 서비스 계정을 가장하도록 역할 결합을 만듭니다.

    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
    

    다음을 바꿉니다.

  6. 서비스 계정이 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을 참조하세요.

  7. 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'
    
    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에서 실행 중인 서버리스 컨테이너를 호출할 수 있습니다. 그러나 해당 단계는 이 튜토리얼에서 다루지 않습니다.

삭제

이 튜토리얼에서 사용한 리소스의 비용이 Google Cloud 계정에 청구되지 않도록 하려면 프로젝트를 삭제하면 됩니다.

프로젝트 삭제

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

다음 단계