워크로드 아이덴티티 제휴를 통해 토큰을 사용하여 인증

이 문서에서는 워크로드 아이덴티티 제휴를 통해 토큰을 사용하여 Google Cloud에 인증하는 방법을 설명합니다. 워크로드 아이덴티티 제휴를 사용하면 서비스 계정 키를 사용하지 않고 온프레미스 또는 멀티 클라우드 SAP 워크로드에 Google Cloud 리소스에 대한 액세스 권한을 부여할 수 있습니다. Amazon Web Services(AWS) 또는 OpenID Connect(OIDC)를 지원하는 ID 공급업체(IdP, 예를 들어 Microsoft Azure 또는 SAML 2.0)에서 워크로드 아이덴티티 제휴를 사용할 수 있습니다.

워크로드 아이덴티티 제휴는 OAuth 2.0 토큰 교환 사양을 따릅니다. IdP의 사용자 인증 정보를 보안 토큰 서비스에 제공하면, 보안 토큰 서비스는 사용자 인증 정보에서 ID를 확인한 후에 대가로 제휴 토큰을 반환합니다. 이 토큰을 사용하여 서비스 계정을 가장하고 단기 OAuth 2.0 액세스 토큰을 받을 수 있습니다. 단기 액세스 토큰을 사용하면 서비스 계정이 액세스할 수 있는 모든 Google Cloud API를 호출할 수 있습니다.

워크로드 아이덴티티 제휴를 통해 토큰을 사용하여 인증하기 위한 대략적인 구성 단계는 다음과 같습니다.

  1. 외부 IdP를 준비합니다.
  2. Google Cloud에서 워크로드 아이덴티티 제휴를 구성합니다.
  3. Google Cloud에서 서비스 계정을 만듭니다.
  4. Google Cloud에서 외부 워크로드가 서비스 계정을 가장하도록 허용합니다.
  5. ABAP SDK for Google Cloud에서 ABAP 코드를 구현하여 IdP에서 보안 토큰을 검색합니다.
  6. ABAP SDK for Google Cloud에서 클라이언트 키를 구성합니다.

모든 Google Cloud 제품에서 워크로드 아이덴티티 제휴를 지원하지 않습니다. 워크로드 아이덴티티 제휴를 사용하여 인증을 설정하기 전에 지원되는 제품 및 제한사항 목록을 검토하세요. 자세한 내용은 직원 ID 제휴: 지원되는 제품 및 제한사항을 참조하세요.

외부 IdP 준비

SAP 워크로드가 Google OAuth 2.0 보안 토큰으로 교환할 수 있는 사용자 인증 정보를 가져올 수 있도록 IdP를 준비해야 합니다.

외부 IdP를 준비하려면 IdP에 따라 다음 단계를 수행합니다.

워크로드 아이덴티티 제휴 구성

Google Cloud에서 워크로드 아이덴티티 풀과 제공업체를 구성합니다.

외부 ID를 관리할 수 있는 항목인 ID 풀을 구성합니다. 또한 Google Cloud와 IdP 사이의 관계를 설명하는 항목인 워크로드 아이덴티티 풀 제공업체를 구성합니다.

워크로드 아이덴티티 제휴를 구성하려면 외부 IdP에 따라 다음 단계를 수행합니다.

다음을 기록해 둡니다.

  • 프로젝트 번호: 워크로드 아이덴티티 풀을 만든 Google Cloud 프로젝트의 프로젝트 번호입니다.
  • 풀 ID: 워크로드 아이덴티티 풀을 식별하는 고유 ID입니다.
  • 제공업체 ID: 워크로드 아이덴티티 풀 제공업체를 식별하는 ID입니다.

ABAP SDK 클라이언트 키 구성에 필요합니다.

서비스 계정 만들기

Google Cloud 콘솔에서 전용 IAM 서비스 계정을 만들어 Google Cloud API에 액세스합니다. 이 서비스 계정은 SDK를 사용할 예정인 Google Cloud API가 포함된 Google Cloud 프로젝트의 주 구성원이어야 합니다.

  1. Google Cloud 콘솔에서 IAM Service Account Credentials API, Security Token Service API, SDK를 사용해 액세스할 계획인 기타 모든 지원 API를 사용 설정합니다.

    API 라이브러리로 이동

    Google Cloud API를 사용 설정하는 방법은 API 사용 설정을 참조하세요.

  2. 워크로드를 나타내는 서비스 계정을 만듭니다.

  3. API 기능에 액세스하는 데 필요한 IAM 역할을 서비스 계정에 부여합니다. Google Cloud API의 역할 요구사항을 이해하려면 개별 API 참고 리소스를 참조하고 최소 권한 원칙을 따릅니다. API별 사전 정의된 역할에 대한 자세한 내용은 Google Cloud API의 IAM 역할 찾기를 참조하세요.

외부 워크로드가 서비스 계정을 가장하도록 허용

외부 워크로드가 서비스 계정을 가장하도록 허용하려면 외부 IdP에 따라 다음 단계를 수행합니다.

ABAP 코드를 구현하여 IdP에서 보안 토큰 검색

ABAP SDK for Google Cloud는 보안 토큰 서비스에서 OAuth 2.0 보안 토큰을 검색하고 IAM Service Account Credentials API에서 OAuth 2.0 액세스 토큰을 검색하는 로직이 있는 추상 클래스 /GOOG/CL_AUTH_WIF_BASE를 제공합니다. 개발자는 추상 클래스 /GOOG/CL_AUTH_WIF_BASE에서 상속되는 하위 클래스를 네임스페이스에 만들어야 합니다.

워크로드 아이덴티티 제휴를 사용하여 ABAP SDK for Google Cloud에서 Cloud Functions를 호출하기 위해 SDK에서 또 다른 추상 클래스 /GOOG/CL_AUTH_WIF_ID_TOKEN을 제공합니다. 워크로드 아이덴티티 제휴를 사용하여 인증을 설정하는 경우 추상 클래스 /GOOG/CL_AUTH_WIF_ID_TOKEN에서 상속되는 하위 클래스 하나 이상을 네임스페이스에 만들어야 합니다. Cloud Functions를 호출하도록 클라이언트 키를 구성하는 동안에 이 하위 클래스를 승인 클래스 필드에 지정합니다.

하위 클래스에서 GET_EXT_IDP_TOKEN 메서드를 구현하고 IdP에서 보안 토큰을 가져오도록 로직을 작성해야 합니다. 다음 필드를 채웁니다.

  • CV_TOKEN: IdP에서 string 형식으로 검색한 토큰입니다.
  • CV_TOKEN_TYPE: IdP에서 검색한 보안 토큰의 유형입니다. 지원되는 토큰 유형은 다음과 같습니다.
    • urn:ietf:params:oauth:token-type:jwt
    • urn:ietf:params:oauth:token-type:id_token
    • urn:ietf:params:aws:token-type:aws4_request
    • urn:ietf:params:oauth:token-type:access_token
    • urn:ietf:params:oauth:token-type:saml2

CV_TOKENCV_TOKEN_TYPE에 채워진 값은 추상 클래스 /GOOG/CL_AUTH_WIF_BASE의 메서드에서 API 호출에 사용되는 최종 OAuth 2.0 토큰을 교환하고 검색하는 데 사용됩니다.

다음 예시에서는 AWS 및 Azure와 같은 다른 클라우드 제공업체에 대한 GET_EXT_IDP_TOKEN 메서드의 샘플 구현을 보여줍니다.

AWS

class ZCL_AUTH_WIF_AWS definition
  public
  inheriting from /GOOG/CL_AUTH_WIF_BASE
  final
  create public .

public section.

  types:
    BEGIN OF t_header_field,
      key type string,
      value TYPE string,
    END OF t_header_field .
  types:
    tt_header_field type STANDARD TABLE OF t_header_field WITH DEFAULT KEY .
  types:
    BEGIN OF t_token_request,
     url type string,
     method type string,
     headers type tt_header_field,
   END OF t_token_request .
protected section.

  methods GET_EXT_IDP_TOKEN
    redefinition .
private section.
ENDCLASS.



CLASS ZCL_AUTH_WIF_AWS IMPLEMENTATION.


METHOD get_ext_idp_token.
**********************************************************************
*  Copyright 2024 Google LLC                                         *
*                                                                    *
*  Licensed under the Apache License, Version 2.0 (the "License");   *
*  you may not use this file except in compliance with the License.  *
*  You may obtain a copy of the License at                           *
*      https://www.apache.org/licenses/LICENSE-2.0                   *
*  Unless required by applicable law or agreed to in writing,        *
*  software distributed under the License is distributed on an       *
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,      *
*  either express or implied.                                        *
*  See the License for the specific language governing permissions   *
*  and limitations under the License.                                *
**********************************************************************

  DATA: ls_key       TYPE /goog/client_key.

  /goog/cl_utility=>get_client_key( EXPORTING iv_keyname    = iv_keyname
                                        IMPORTING es_client_key = ls_key ).


  DATA: lv_awsdate TYPE string.

  DATA: lv_date         TYPE dats,
        lv_time         TYPE tims,
        lv_timestamp    TYPE timestampl,
        lv_tz_utc       TYPE timezone VALUE 'UTC',
        lv_awsts        TYPE string,
        lv_timechar(32) TYPE c.

  GET TIME STAMP FIELD lv_timestamp.

  CONVERT TIME STAMP lv_timestamp TIME ZONE lv_tz_utc INTO DATE lv_date TIME lv_time.
  MOVE lv_timestamp TO lv_timechar.
  CONDENSE lv_timechar.

  lv_awsdate = lv_date(4) &&
               lv_date+4(2) &&
               lv_date+6(2) &&
               'T' &&
               lv_time(2) &&
               lv_time+2(2) &&
               lv_time+4(2) &&
               'Z'.

  TRANSLATE lv_awsdate TO UPPER CASE.

  DATA: lv_lf TYPE string.
  DATA: lv_secret_key TYPE string.
  DATA: lv_accesskey TYPE string.
  DATA: lv_datepart TYPE string.
  DATA: lv_service TYPE string.
  DATA: lv_method TYPE string.

  lv_lf = cl_abap_char_utilities=>newline.
  lv_accesskey = '<Populate AWS Access Key>'.
  lv_secret_key = '<Populate AWS Secret Access Key>'.
  lv_datepart = lv_awsdate(8).
  lv_service = 'sts'.
  lv_method = 'GET'.


  DATA: lv_canonical_query_params TYPE string.
  DATA: lv_host TYPE string.
  DATA: lv_region TYPE string.
  DATA: lv_canonical_resource_path TYPE string.

  lv_canonical_query_params = 'Action=GetCallerIdentity&Version=2011-06-15'.
  lv_host = 'sts.amazonaws.com'.
  lv_region = '<Populate your AWS Region>'.   "Example: 'us-east-1'
  lv_canonical_resource_path = '/'.

  DATA: lv_canonical_header_names TYPE string.
  DATA: lv_canonical_headers TYPE string.

  lv_canonical_header_names = 'host;x-amz-date'.
  lv_canonical_headers = 'host:' && lv_host && lv_lf && 'x-amz-date:' && lv_awsdate && lv_lf.

  DATA: lv_canonical_request TYPE string.

  CONCATENATE lv_method lv_lf
              lv_canonical_resource_path lv_lf
              lv_canonical_query_params lv_lf
              lv_canonical_headers lv_lf
              lv_canonical_header_names
              INTO lv_canonical_request.

  DATA: lv_canonical_request_hash TYPE string.

  TRY.
      cl_abap_message_digest=>calculate_hash_for_char(
       EXPORTING
         if_algorithm = 'SHA-256'
         if_data = lv_canonical_request
       IMPORTING
         ef_hashstring = lv_canonical_request_hash ).
    CATCH cx_abap_message_digest.
      "Handle error
      RETURN.
  ENDTRY.

  TRANSLATE lv_canonical_request_hash TO LOWER CASE.

  DATA: lv_algorithm TYPE string.

  lv_algorithm = 'AWS4-HMAC-SHA256'.

  DATA: lv_credential_scope TYPE string.

  CONCATENATE lv_datepart '/' lv_region '/' lv_service '/' 'aws4_request' INTO lv_credential_scope.

  DATA: lv_string_to_sign TYPE string.

  CONCATENATE lv_algorithm lv_lf
              lv_awsdate lv_lf
              lv_credential_scope lv_lf
              lv_canonical_request_hash
              INTO lv_string_to_sign.

  DATA: lv_awskey TYPE string.

  CONCATENATE 'AWS4' lv_secret_key INTO lv_awskey.

  DATA: lv_ksecret TYPE xstring.

  TRY.
      lv_ksecret = cl_abap_hmac=>string_to_xstring( lv_awskey ).
    CATCH cx_abap_message_digest .
      "Handle error
      RETURN.
  ENDTRY.

  DATA: lv_kdate  TYPE xstring.
  TRY.
      cl_abap_hmac=>calculate_hmac_for_char(
        EXPORTING
           if_algorithm = 'SHA256'
           if_key = lv_ksecret
           if_data = lv_datepart
        IMPORTING
           ef_hmacxstring = lv_kdate ).
    CATCH cx_abap_message_digest. "
      "Handle error
      RETURN.
  ENDTRY.

  DATA: lv_kregion TYPE xstring.
  TRY.
      cl_abap_hmac=>calculate_hmac_for_char(
        EXPORTING
           if_algorithm = 'SHA256'
           if_key = lv_kdate
           if_data = lv_region
        IMPORTING
             ef_hmacxstring = lv_kregion ).
    CATCH cx_abap_message_digest.
      "Handle error
      RETURN.
  ENDTRY.

  DATA: lv_kservice TYPE xstring.
  TRY.
      cl_abap_hmac=>calculate_hmac_for_char(
         EXPORTING
           if_algorithm = 'SHA256'
           if_key = lv_kregion
           if_data = lv_service
           IMPORTING
             ef_hmacxstring = lv_kservice ).
    CATCH cx_abap_message_digest.
      "Handle error
      RETURN.
  ENDTRY.

  DATA: lv_ksigningkey TYPE xstring.
  TRY.
      cl_abap_hmac=>calculate_hmac_for_char(
         EXPORTING
           if_algorithm = 'SHA256'
           if_key = lv_kservice
           if_data = 'aws4_request'
         IMPORTING
             ef_hmacxstring = lv_ksigningkey ).
    CATCH cx_abap_message_digest.
      "Handle error
      RETURN.
  ENDTRY.

  DATA: lv_stringtosign TYPE string.

  lv_stringtosign = 'AWS4-HMAC-SHA256' && lv_lf &&
                   lv_awsdate && lv_lf &&
                   lv_datepart && '/' &&
                   lv_region && '/' &&
                   lv_service && '/aws4_request' && lv_lf &&
                   lv_canonical_request_hash.

  DATA: lv_ssignature TYPE string.

  TRY.
      cl_abap_hmac=>calculate_hmac_for_char(
         EXPORTING
           if_algorithm = 'SHA256'
           if_key = lv_ksigningkey
           if_data = lv_stringtosign
         IMPORTING
           ef_hmacstring = lv_ssignature ).
    CATCH cx_abap_message_digest.
      "Handle error
      RETURN.
  ENDTRY.

  TRANSLATE lv_ssignature TO LOWER CASE.

  DATA: lv_authorization_header TYPE string.

  lv_authorization_header = 'AWS4-HMAC-SHA256 Credential=' &&
                            lv_accesskey && '/' &&
                            lv_credential_scope &&
                            ', SignedHeaders=' &&
                            lv_canonical_header_names &&
                            ', Signature=' &&
                            lv_ssignature.

  DATA: ls_token_request TYPE t_token_request.

  ls_token_request-url = 'https://sts.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15'.
  ls_token_request-method = 'POST'.

  DATA: ls_header_field TYPE t_header_field.
  ls_header_field-key = 'Authorization'.
  ls_header_field-value = lv_authorization_header.
  APPEND ls_header_field TO ls_token_request-headers.

  CLEAR: ls_header_field.
  ls_header_field-key = 'host'.
  ls_header_field-value = 'sts.amazonaws.com'.
  APPEND ls_header_field TO ls_token_request-headers.

  CLEAR: ls_header_field.
  ls_header_field-key = 'x-amz-date'.
  ls_header_field-value = lv_awsdate.
  APPEND ls_header_field TO ls_token_request-headers.

  CLEAR: ls_header_field.
  ls_header_field-key = 'x-goog-cloud-target-resource'.
  ls_header_field-value = '//iam.googleapis.com/projects/' &&
                               ls_key-project_id &&
                               '/locations/global/workloadIdentityPools/' &&
                               ls_key-auth_param1 &&
                               '/providers/' &&
                               ls_key-auth_param2.
  APPEND ls_header_field TO ls_token_request-headers.

  cv_token = /ui2/cl_json=>serialize(  ls_token_request ).
  cv_token_type = 'urn:ietf:params:aws:token-type:aws4_request'.

ENDMETHOD.
ENDCLASS.

Azure

class ZCL_AUTH_WIF_AZURE definition
  public
  inheriting from /GOOG/CL_AUTH_WIF_BASE
  final
  create public .

public section.
protected section.

  methods GET_EXT_IDP_TOKEN
    redefinition .
private section.
ENDCLASS.



CLASS ZCL_AUTH_WIF_AZURE IMPLEMENTATION.


  METHOD GET_EXT_IDP_TOKEN.
**********************************************************************
*  Copyright 2024 Google LLC                                         *
*                                                                    *
*  Licensed under the Apache License, Version 2.0 (the "License");   *
*  you may not use this file except in compliance with the License.  *
*  You may obtain a copy of the License at                           *
*      https://www.apache.org/licenses/LICENSE-2.0                   *
*  Unless required by applicable law or agreed to in writing,        *
*  software distributed under the License is distributed on an       *
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,      *
*  either express or implied.                                        *
*  See the License for the specific language governing permissions   *
*  and limitations under the License.                                *
**********************************************************************

    TYPES:
      BEGIN OF t_azure_resp,
        access_token TYPE string,
      END OF t_azure_resp.

    DATA: lo_client TYPE REF TO if_http_client.

    DATA: lv_url type string.
    lv_url = 'http://169.254.169.254/metadata/identity/oauth2/token?resource=<APP_ID_URI>&api-version=2018-02-01'.
    "Replace <APP_ID_URI> with the value of Application ID URI of the application that you've configured for workload identity federation.

    cl_http_client=>create_by_url(
       EXPORTING
         url                        = lv_url
       IMPORTING
         client                     = lo_client
       EXCEPTIONS
         argument_not_found         = 1
         plugin_not_active          = 2
         internal_error             = 3
         pse_not_found              = 4
         pse_not_distrib            = 5
         pse_errors                 = 6
         oa2c_set_token_error       = 7
         oa2c_missing_authorization = 8
         oa2c_invalid_config        = 9
         oa2c_invalid_parameters    = 10
         oa2c_invalid_scope         = 11
         oa2c_invalid_grant         = 12
         OTHERS                     = 13 ).

    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    lo_client->request->set_method( 'GET' ).
    lo_client->request->set_header_field( name = 'Metadata' value = 'true' ).

    lo_client->send(
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3
        http_invalid_timeout       = 4
        OTHERS                     = 5 ).

    lo_client->propertytype_logon_popup = lo_client->co_disabled.

    lo_client->receive(
      EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3 ).

    DATA: lv_json TYPE string.

    lv_json = lo_client->response->get_cdata( ).

    DATA: ls_azure_resp TYPE t_azure_resp.

    /goog/cl_json=>deserialize(
      EXPORTING
        json             = lv_json
      CHANGING
        data             = ls_azure_resp ).
    cv_token = ls_azure_resp-access_token.
    cv_token_type = 'urn:ietf:params:oauth:token-type:jwt'.

  ENDMETHOD.
ENDCLASS.

클라이언트 키 구성

  1. SAP GUI에서 트랜잭션 코드 /GOOG/SDK_IMG를 실행합니다.

    또는 트랜잭션 코드 SPRO를 실행한 후 SAP 참조 IMG를 클릭합니다.

  2. ABAP SDK for Google Cloud > 기본 설정 > 클라이언트 키 구성을 클릭합니다.
  3. 새 항목을 클릭합니다.
  4. 다음 필드에 값을 입력합니다.

    필드 설명
    Google Cloud 키 이름 클라이언트 키 구성의 이름을 지정합니다.
    Google Cloud 서비스 계정 이름 서비스 계정 만들기 단계에서 Google Cloud API에 액세스하도록 만든 서비스 계정의 이름을 이메일 주소 형식으로 지정합니다. 예를 들면 sap-example-svc-acct@example-project-123456.iam.gserviceaccount.com입니다.
    Google Cloud 범위 이 입력란은 비워둡니다.
    Google Cloud 프로젝트 식별자 워크로드 아이덴티티 풀을 만든 Google Cloud 프로젝트의 ID를 지정합니다.
    명령어 이름 이 입력란은 비워둡니다.
    승인 클래스 /GOOG/CL_AUTH_WIF_BASE 클래스 구현이 포함된 하위 클래스를 지정합니다. 자세한 내용은 ABAP 코드를 구현하여 IdP에서 보안 토큰 검색을 참조하세요.
    토큰 캐싱 이 입력란은 비워둡니다.
    토큰 새로고침 시간(초) 이 입력란은 비워둡니다.
    승인 매개변수 1 워크로드 아이덴티티 풀 ID를 지정합니다.
    승인 매개변수 2 워크로드 아이덴티티 공급업체 ID를 지정합니다.
  5. 항목을 저장합니다.

지원받기

ABAP SDK for Google Cloud 문제를 해결하는 데 도움이 필요한 경우 다음을 수행하세요.