Melakukan autentikasi menggunakan token melalui Workload Identity Federation

Dokumen ini menjelaskan cara melakukan autentikasi ke Google Cloud dengan menggunakan token melalui Workload Identity Federation. Dengan Workload Identity Federation, Anda dapat memberikan akses workload SAP lokal atau multicloud ke Google Cloud resource tanpa menggunakan kunci akun layanan. Anda dapat menggunakan Workload Identity Federation dengan Amazon Web Services (AWS) atau dengan penyedia identitas (IdP) yang mendukung OpenID Connect (OIDC), seperti seperti Microsoft Azure atau SAML 2.0.

Workload Identity Federation mengikuti Pertukaran token OAuth 2.0 spesifikasi pendukung. Anda memberikan kredensial dari IdP ke Layanan Token Keamanan, yang memverifikasi identitas pada kredensial, lalu menampilkan token federasi sebagai gantinya. Anda dapat menggunakan token ini untuk meniru identitas akun layanan dan memperoleh token akses OAuth 2.0 yang berumur pendek. Token akses jangka pendek memungkinkan Anda memanggil semua Google Cloud API yang dapat diakses oleh akun layanan.

Untuk autentikasi menggunakan token melalui Workload Identity Federation, langkah-langkah konfigurasi tingkat tinggi adalah sebagai berikut:

  1. Siapkan IdP eksternal.
  2. Di Google Cloud, konfigurasikan Workload Identity Federation.
  3. Di Google Cloud, buat akun layanan.
  4. Di Google Cloud, izinkan workload eksternal untuk meniru identitas akun layanan.
  5. Di ABAP SDK for Google Cloud, terapkan kode ABAP untuk mengambil token keamanan dari IdP Anda.
  6. Di ABAP SDK untuk Google Cloud, konfigurasi kunci klien.

Tidak semua produk Google Cloud mendukung Workload Identity Federation. Sebelum menyiapkan autentikasi menggunakan Workload Identity Federation, tinjau daftar produk dan batasan yang didukung. Untuk mengetahui informasi selengkapnya, lihat Penggabungan identitas tenaga kerja: produk dan batasan yang didukung.

Menyiapkan IdP eksternal Anda

Anda harus menyiapkan IdP sehingga beban kerja SAP Anda dapat memperoleh kredensial yang dapat ditukar dengan token keamanan Google OAuth 2.0.

Untuk menyiapkan IdP eksternal, lakukan langkah-langkah bergantung pada IdP Anda:

Mengonfigurasi Workload Identity Federation

Di Google Cloud, konfigurasikan kumpulan dan penyedia workload identity.

Anda mengonfigurasi kumpulan identitas, yaitu entitas yang memungkinkan Anda mengelola identitas eksternal. Anda juga akan mengonfigurasi penyedia workload identity pool, yang merupakan entity yang menggambarkan hubungan antara Google Cloud dan IdP Anda.

Untuk mengonfigurasi Workload Identity Federation, lakukan langkah-langkah sesuai kebutuhan di IdP eksternal:

Catat hal-hal berikut:

  • Project number: nomor project project Google Cloud dengan Anda membuat kumpulan workload identity.
  • ID Kumpulan: ID unik yang mengidentifikasi kumpulan identitas workload.
  • ID Penyedia: ID yang mengidentifikasi penyedia kumpulan workload identity.

Anda memerlukannya untuk konfigurasi kunci klien ABAP SDK.

Membuat akun layanan

Di konsol Google Cloud, buat IAM khusus akun layanan Anda untuk mengakses Google Cloud API. Akun layanan ini harus merupakan akun utama dalam project Google Cloud yang berisi Google Cloud API yang akan Anda gunakan dengan menggunakan SDK.

  1. Di Konsol Google Cloud, aktifkan IAM Service Account Credentials API, Security Token Service API, dan semua API lain yang didukung yang akan Anda akses menggunakan SDK.

    Buka koleksi API

    Untuk mengetahui informasi tentang cara mengaktifkan Google Cloud API, lihat Mengaktifkan API.

  2. Buat akun layanan yang merepresentasikan workload.

  3. Memberikan peran IAM yang diperlukan kepada akun layanan untuk mengakses fungsi API. Guna memahami persyaratan peran untuk Google Cloud API, melihat dokumentasi API individual dan ikuti prinsip hak istimewa terendah. Untuk selengkapnya mengetahui informasi tentang peran bawaan khusus API, lihat Menemukan peran IAM untuk Google Cloud API.

Mengizinkan workload eksternal untuk meniru identitas akun layanan

Agar beban kerja eksternal meniru akun layanan, lakukan tindakan langkah-langkah, bergantung pada IdP eksternal Anda:

Menerapkan kode ABAP untuk mengambil token keamanan dari IdP Anda

ABAP SDK untuk Google Cloud menyediakan class abstrak /GOOG/CL_AUTH_WIF_BASE, yang memiliki logika untuk mengambil token keamanan OAuth 2.0 dari layanan Token Keamanan dan token akses OAuth 2.0 dari IAM Service Account Credentials API. Sebagai pengembang, Anda perlu buat class turunan di namespace Anda yang mewarisi dari class abstrak /GOOG/CL_AUTH_WIF_BASE.

Untuk memanggil fungsi Cloud Run dari ABAP SDK untuk Google Cloud menggunakan Workload Identity Federation, SDK menyediakan class abstrak lainnya /GOOG/CL_AUTH_WIF_ID_TOKEN. Jika Anda menyiapkan autentikasi menggunakan Workload Identity Federation, lalu Anda perlu membuat satu lagi di namespace Anda yang diwarisi dari class abstrak /GOOG/CL_AUTH_WIF_ID_TOKEN. Anda menentukan kelas turunan ini kolom Authorization Class saat mengonfigurasi kunci klien untuk memanggil fungsi Cloud Run.

Pastikan untuk menerapkan metode GET_EXT_IDP_TOKEN di class turunan dan tulis logika untuk mendapatkan token keamanan dari IdP Anda. Isi kolom berikut:

  • CV_TOKEN: token yang diambil dari IdP Anda dalam format string.
  • CV_TOKEN_TYPE: jenis token keamanan yang diambil dari IdP Anda. Jenis token yang didukung adalah:
    • 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

Nilai yang diisi dalam CV_TOKEN dan CV_TOKEN_TYPE kemudian digunakan oleh metode class abstrak /GOOG/CL_AUTH_WIF_BASE untuk bertukar dan mengambil token OAuth 2.0 final, yang digunakan dalam panggilan API.

Contoh berikut menunjukkan contoh implementasi metode GET_EXT_IDP_TOKEN untuk penyedia Cloud lain, seperti AWS dan Azure.

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.

Mengonfigurasi kunci klien

  1. Di GUI SAP, jalankan kode transaksi /GOOG/SDK_IMG.

    Atau, jalankan kode transaksi SPRO, lalu klik SAP Reference IMG.

  2. Klik ABAP SDK for Google Cloud &gt; Setelan Dasar &gt; Konfigurasi Kunci Klien.
  3. Klik New Entries.
  4. Masukkan nilai untuk kolom berikut:

    Kolom Deskripsi
    Nama Kunci Google Cloud Tentukan nama konfigurasi kunci klien.
    Nama Akun Layanan Google Cloud Tentukan nama akun layanan, dalam format alamat email, yang dibuat untuk mengakses Google Cloud API dalam langkah Buat akun layanan. Contoh: sap-example-svc-acct@example-project-123456.iam.gserviceaccount.com.
    Cakupan Google Cloud Kosongkan kolom ini.
    ID Project Google Cloud Tentukan ID project Google Cloud tempat Anda membuat workload identity pool.
    Nama perintah Kosongkan kolom ini.
    Kelas Otorisasi Menentukan class turunan yang berisi implementasi dari class /GOOG/CL_AUTH_WIF_BASE. Untuk informasi selengkapnya, lihat Terapkan kode ABAP untuk mengambil token keamanan dari IdP Anda.
    Pembuatan Cache Token Kosongkan kolom ini.
    detik Token Refresh Kosongkan kolom ini.
    Parameter Otorisasi 1 Tentukan ID kumpulan workload identity.
    Parameter Otorisasi 2 Tentukan ID penyedia workload identity.
  5. Simpan entri.

Mendapatkan dukungan

Jika Anda memerlukan bantuan untuk menyelesaikan masalah dengan ABAP SDK untuk Google Cloud, lakukan hal berikut: