אימות פרוגרמטי

במאמר הזה מוסבר איך לבצע אימות למשאב שמאובטח באמצעות IAP מחשבון משתמש או מחשבון שירות.

גישה פרוגרמטית מתייחסת לקריאה לאפליקציות שמאובטחות באמצעות IAP מלקוחות שאינם דפדפנים, כמו כלי שורת פקודה, קריאות משירות לשירות ואפליקציות לנייד. בהתאם לתרחיש לדוגמה, יכול להיות שתרצו לבצע אימות ל-IAP באמצעות פרטי כניסה של משתמש או של שירות.

  • חשבון משתמש שייך למשתמש ספציפי. אתם מאמתים חשבון משתמש כשהאפליקציה שלכם דורשת גישה למשאבים שמאובטחים באמצעות IAP בשם המשתמש. מידע נוסף זמין במאמר חשבונות משתמשים.

  • חשבון שירות מייצג אפליקציה במקום משתמש פרטי. כדי לאפשר לאפליקציה לגשת למשאבים שמאובטחים באמצעות IAP, צריך לאמת את חשבון השירות. מידע נוסף זמין במאמר חשבונות שירות.

IAP תומך בסוגים הבאים של פרטי כניסה לגישה פרוגרמטית:

* טוקן של מזהה מסוג OAuth 2.0 – אסימון שהונפק על ידי Google למשתמש אנושי או לחשבון שירות, עם הצהרת הקהל שמוגדרת למזהה המשאב של אפליקציית IAP. * ‏JWT חתום בחשבון שירות – אסימון JWT בחתימה עצמית או שהונפק על ידי Google בשביל חשבון שירות.

צריך לכלול את פרטי הכניסה האלה ל-IAP בכותרת ה-HTTP‏ Authorization או Proxy-Authorization של הבקשה.

לפני שמתחילים

  1. מוודאים שיש לכם אפליקציה שאתם רוצים לגשת אליה באופן פרוגרמטי באמצעות חשבון פיתוח, חשבון שירות או פרטי כניסה לאפליקציה לנייד.

  2. איך יוצרים לקוחות OAuth 2.0?

אימות של חשבון משתמש

אתם יכולים לאפשר למשתמשים לגשת לאפליקציה שלכם ממחשב או מאפליקציה לנייד, כדי שתוכנה תוכל לקיים אינטראקציה עם משאב שמאובטח באמצעות IAP.

אימות באמצעות אפליקציה לנייד

  1. יוצרים או משתמשים במזהה לקוח קיים של OAuth 2.0 לאפליקציה לנייד. כדי להשתמש במזהה לקוח קיים של OAuth 2.0, פועלים לפי השלבים שמפורטים במאמר איך משתפים לקוחות OAuth. מוסיפים את מזהה הלקוח ב-OAuth לרשימת ההיתרים כדי לאפשר גישה פרוגרמטית לאפליקציה.
  2. מקבלים טוקן של מזהה למזהה הלקוח ב-OAuth 2.0 של המשאב שמאובטח באמצעות IAP.
  3. כדי לשלוח את הבקשה המאומתת למשאב שמאובטח באמצעות IAP, צריך לכלול את טוקן של מזהה בכותרת Authorization: Bearer.

אימות מאפליקציה למחשב

בקטע הזה מוסבר איך לאמת חשבון משתמש משורת הפקודה במחשב.

  1. כדי לאפשר למפתחים לגשת לאפליקציה משורת הפקודה, צרו מזהה לקוח OAuth 2.0 למחשב או שתפו מזהה לקוח OAuth קיים למחשב.
  2. מוסיפים את מזהה ה-OAuth לרשימת ההיתרים של הגישה הפרוגרמטית לאפליקציה.

נכנסים לאפליקציה.

כל מפתח צריך להיכנס לחשבון כדי לגשת לאפליקציה שמאובטחת באמצעות IAP. אפשר לארוז את התהליך בסקריפט, למשל באמצעות ה-CLI של gcloud. בדוגמה הבאה משתמשים ב-curl כדי להיכנס וליצור אסימון שאפשר להשתמש בו כדי לגשת לאפליקציה:

  1. נכנסים לחשבון שיש לו גישה למשאב Google Cloud .
  2. מפעילים שרת מקומי שיכול להדהד את הבקשות הנכנסות.

      # Example using Netcat (http://netcat.sourceforge.net/)
      nc -k -l 4444
    
  3. עוברים ל-URI הבא, כאשר DESKTOP_CLIENT_ID הוא מזהה הלקוח של האפליקציה למחשב:

      https://accounts.google.com/o/oauth2/v2/auth?client_id=DESKTOP_CLIENT_ID&response_type=code&scope=openid%20email&access_type=offline&redirect_uri=http://localhost:4444&cred_ref=true
    
  4. בפלט של השרת המקומי, מחפשים את הפרמטרים של הבקשה:

      GET /?code=CODE&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email&hd=google.com&prompt=consent HTTP/1.1
    
  5. מעתיקים את הערך CODE כדי להחליף את CODE בפקודה הבאה, יחד עם מזהה הלקוח והסוד של אפליקציה למחשב:

      curl --verbose \
        --data client_id=DESKTOP_CLIENT_ID \
        --data client_secret=DESKTOP_CLIENT_SECRET \
        --data code=CODE \
        --data redirect_uri=http://localhost:4444 \
        --data grant_type=authorization_code \
        https://oauth2.googleapis.com/token
    

    הפקודה הזו מחזירה אובייקט JSON עם שדה id_token שבו אפשר להשתמש כדי לגשת לאפליקציה.

גישה לאפליקציה

כדי לגשת לאפליקציה, משתמשים בid_token:

curl --verbose --header 'Authorization: Bearer ID_TOKEN' URL

טוקן רענון

אתם יכולים להשתמש בטוקן הרענון שנוצר במהלך תהליך הכניסה כדי לקבל טוקנים חדשים של מזהים. זה שימושי כשהתוקף של טוקן המזהה המקורי פג. כל טוקן של מזהה תקף למשך כשעה, ובמהלך הזמן הזה אפשר לשלוח כמה בקשות לאפליקציה ספציפית.

בדוגמה הבאה משתמשים ב-curl כדי להשתמש בטוקן הרענון ולקבל טוקן חדש של מזהה. בדוגמה הזו, REFRESH_TOKEN הוא הטוקן מתהליך הכניסה. ‫DESKTOP_CLIENT_ID ו-DESKTOP_CLIENT_SECRET זהים לאלה שמשמשים בתהליך הכניסה:

curl --verbose \
  --data client_id=DESKTOP_CLIENT_ID \
  --data client_secret=DESKTOP_CLIENT_SECRET \
  --data refresh_token=REFRESH_TOKEN \
  --data grant_type=refresh_token \
  https://oauth2.googleapis.com/token

הפקודה הזו מחזירה אובייקט JSON עם שדה id_token חדש, שבו אפשר להשתמש כדי לגשת לאפליקציה.

אימות של חשבון שירות

כדי לאמת חשבון שירות באמצעות משאב שמאובטח על ידי IAP, אתם יכולים להשתמש באסימון JWT של חשבון שירות או באסימון OpenID Connect ‏(OIDC). בטבלה הבאה מפורטים חלק מההבדלים בין אסימוני האימות השונים והתכונות שלהם.

תכונות אימות ‫JWT של חשבון שירות אסימון OpenID Connect
תמיכה בבקרת גישה מבוססת-הקשר
דרישה למזהה לקוח ב-OAuth 2.0
היקף הטוקן כתובת ה-URL של המשאב שמאובטח באמצעות IAP מזהה לקוח ב-OAuth 2.0

אימות באמצעות JWT של חשבון שירות

ב-IAP יש תמיכה באימות JWT של חשבון שירות ל-Google Identity, ל-Identity Platform ולאפליקציות שהוגדרו לאיחוד שירותי אימות הזהות של כוח העבודה.

כדי לאמת חשבון שירות באמצעות JWT, צריך לבצע את השלבים הבאים:

  1. מקצים לחשבון השירות שמבצע את הקריאה את התפקיד יצירת אסימונים בחשבון שירות (roles/iam.serviceAccountTokenCreator).

    התפקיד נותן לחשבונות משתמשים הרשאה ליצור פרטי כניסה לטווח קצר, כמו אסימוני JWT.

  2. יוצרים JWT למשאב שמאובטח באמצעות IAP.

  3. חותמים על ה-JWT באמצעות המפתח הפרטי של חשבון השירות.

יצירת ה-JWT

ה-JWT שנוצר אמור להכיל מטען ייעודי (payload) שדומה לדוגמה הבאה:

{
  "iss": SERVICE_ACCOUNT_EMAIL_ADDRESS,
  "sub": SERVICE_ACCOUNT_EMAIL_ADDRESS,
  "aud": TARGET_URL,
  "iat": IAT,
  "exp": EXP,
}
  • בשדות iss ו-sub, מציינים את כתובת האימייל של חשבון השירות. כתובת האימייל נמצאת בשדה client_email של קובץ ה-JSON של חשבון השירות, או שהיא מסופקת כקלט. פורמט אופייני: service-account@PROJECT_ID.iam.gserviceaccount.com

  • בשדה aud, מציינים את כתובת ה-URL המדויקת או את כתובת ה-URL עם תו כללי לחיפוש נתיב (/*) של המשאב שמאובטח באמצעות IAP, לדוגמה https://example.com/ או https://example.com/*. אסימון JWT עם כתובת ה-URL המדויקת בשדה aud יכול לגשת רק לכתובת ה-URL הספציפית הזו. אסימון JWT עם התו הכללי לחיפוש של הנתיב (/*) בשדה aud יכול לגשת לכל כתובות ה-URL עם הקידומת של המחרוזת aud בלי התו * בסוף.

  • בשדה iat, מציינים את ראשית זמן יוניקס (Unix epoch) הנוכחי, ובשדה exp מציינים זמן בטווח של 3, 600 שניות לאחר מכן. השדה הזה מגדיר מתי פג התוקף של ה-JWT.

חתימה על ה-JWT

אפשר להשתמש באחת מהשיטות הבאות כדי לחתום על ה-JWT:

  • משתמשים ב-IAM credentials API כדי לחתום על JWT בלי צורך בגישה ישירה למפתח פרטי.
  • משתמשים בקובץ מפתח של פרטי כניסה מקומיים כדי לחתום על ה-JWT באופן מקומי.
חתימה על ה-JWT באמצעות IAM Service Account Credentials API

משתמשים ב-IAM Service Account Credentials API כדי לחתום על JWT של חשבון שירות. ה-method מאחזרת את המפתח הפרטי שמשויך לחשבון השירות ומשתמשת בו כדי לחתום על המטען הייעודי (payload) של ה-JWT. כך אפשר לחתום על JWT בלי גישה ישירה למפתח פרטי.

כדי לבצע אימות ב-IAP, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

gcloud

  1. מריצים את הפקודה הבאה כדי להכין בקשה עם ה-payload של ה-JWT:
cat > claim.json << EOM
{
  "iss": "SERVICE_ACCOUNT_EMAIL_ADDRESS",
  "sub": "SERVICE_ACCOUNT_EMAIL_ADDRESS",
  "aud": "TARGET_URL",
  "iat": $(date +%s),
  "exp": $((`date +%s` + 3600))
}
EOM
  1. משתמשים בפקודה הבאה של Google Cloud CLI כדי לחתום על המטען הייעודי (payload) ב-claim.json:
gcloud iam service-accounts sign-jwt --iam-account="SERVICE_ACCOUNT_EMAIL_ADDRESS" claim.json output.jwt

אחרי שהבקשה תאושר, output.jwt יכיל JWT חתום שבו תוכלו להשתמש כדי לגשת למשאב שמאובטח באמצעות IAP.

Python

import datetime
import json

import google.auth
from google.cloud import iam_credentials_v1

def generate_jwt_payload(service_account_email: str, resource_url: str) -> str:
    """Generates JWT payload for service account.

    Creates a properly formatted JWT payload with standard claims (iss, sub,
    aud, iat, exp) needed for IAP authentication.

    Args:
        service_account_email (str): Specifies the service account that the
        JWT is created for.
        resource_url (str): Specifies the scope of the JWT, the URL that the
        JWT will be allowed to access.

    Returns:
        str: JSON string containing the JWT payload with properly formatted
        claims.
    """
    # Create current time and expiration time (1 hour later) in UTC
    iat = datetime.datetime.now(tz=datetime.timezone.utc)
    exp = iat + datetime.timedelta(seconds=3600)

    # Convert datetime objects to numeric timestamps (seconds since epoch)
    # as required by JWT standard (RFC 7519)
    payload = {
        "iss": service_account_email,
        "sub": service_account_email,
        "aud": resource_url,
        "iat": int(iat.timestamp()),
        "exp": int(exp.timestamp()),
    }

    return json.dumps(payload)

def sign_jwt(target_sa: str, resource_url: str) -> str:
    """Signs JWT payload using ADC and IAM credentials API.

    Uses Google Cloud's IAM Credentials API to sign a JWT. This requires the
    caller to have iap.webServiceVersions.accessViaIap permission on the
    target service account.

    Args:
        target_sa (str): Service Account JWT is being created for.
            iap.webServiceVersions.accessViaIap permission is required.
        resource_url (str): Audience of the JWT and scope of the JWT token.
            This is the URL of the IAP-secured application.

    Returns:
        str: A signed JWT that can be used to access IAP-secured applications.
            Use in Authorization header as: 'Bearer <signed_jwt>'
    """
    # Get default credentials from environment or application credentials
    source_credentials, project_id = google.auth.default()

    # Initialize IAM credentials client with source credentials
    iam_client = iam_credentials_v1.IAMCredentialsClient(credentials=source_credentials)

    # Generate the service account resource name.
    # Project should always be "-".
    # Replacing the wildcard character with a project ID is invalid.
    name = iam_client.service_account_path("-", target_sa)

    # Create and sign the JWT payload
    payload = generate_jwt_payload(target_sa, resource_url)

    # Sign the JWT using the IAM credentials API
    response = iam_client.sign_jwt(name=name, payload=payload)

    return response.signed_jwt

curl

  1. מריצים את הפקודה הבאה כדי להכין בקשה עם ה-payload של ה-JWT:

    cat << EOF > request.json
    {
      "payload": JWT_PAYLOAD
    }
    EOF
    
  2. חתימה על ה-JWT באמצעות IAM

    ‫Service Account Credentials API:

    curl -X POST \
      -H "Authorization: Bearer $(gcloud auth print-access-token)" \
      -H "Content-Type: application/json; charset=utf-8" \
      -d @request.json \
      "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL_ADDRESS:signJwt"
    

    אחרי שהבקשה תאושר, יוחזר בתגובה JWT חתום.

  3. משתמשים ב-JWT כדי לגשת למשאב שמאובטח באמצעות IAP.

חתימה על ה-JWT מקובץ מפתח של פרטי כניסה מקומיים

אסימוני JWT נחתמים באמצעות המפתח הפרטי של חשבון השירות.

אם יש לכם קובץ מפתח של חשבון שירות, אתם יכולים לחתום על ה-JWT באופן מקומי.

כשחותמים על ה-JWT באופן מקומי, צריך לכלול כותרת JWT עם המטען הייעודי (payload). בשדה kid שבכותרת, משתמשים במזהה המפתח הפרטי של חשבון השירות, שנמצא בשדה private_key_id בקובץ ה-JSON של פרטי הכניסה לחשבון השירות. המפתח הפרטי מהקובץ משמש לחתימה על ה-JWT.

גישה לאפליקציה

כדי לגשת לאפליקציה, צריך לכלול את ה-JWT החתום בכותרת Authorization:

curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL

אימות באמצעות אסימון OIDC של חשבון שירות

כדי לבצע אימות באמצעות אסימון OIDC של חשבון שירות:

  1. יוצרים מזהה לקוח חדש של OIDC או משתמשים במזהה קיים.

    • כדי ליצור מזהה לקוח חדש ב-OAuth 2.0:

      1. אם עדיין לא עשיתם זאת, ודאו שרשמתם את האפליקציה שלכם לשימוש באימות של Google.

      2. עוברים לדף Google Auth Platform.

        כניסה לפלטפורמת האימות של Google

        אם לא בחרתם פרויקט, תתבקשו ליצור פרויקט.

      3. לוחצים על Create Client.

      4. בוחרים את סוג האפליקציה המתאים ומזינים את כל המידע הנוסף שנדרש.

      5. ממלאים את הפרטים הנדרשים לסוג הלקוח שנבחר. כדי ליצור את הלקוח, לוחצים על Create.

    • כדי להשתמש במזהה לקוח קיים של OAuth 2.0: פועלים לפי השלבים שמפורטים במאמר איך משתפים לקוחות OAuth.

  2. מוסיפים את מזהה ה-OAuth לרשימת ההיתרים של הגישה הפרוגרמטית לאפליקציה.

  3. מוודאים שחשבון השירות שמוגדר כברירת מחדל נוסף לרשימת הגישה של הפרויקט שמאובטח באמצעות IAP.

כששולחים בקשות למשאב שמאובטח באמצעות IAP, צריך לכלול את האסימון בכותרת Authorization: Authorization: 'Bearer OIDC_TOKEN'

דוגמאות הקוד הבאות ממחישות איך לקבל אסימון OIDC.

קבלת אסימון OIDC לחשבון השירות שמוגדר כברירת מחדל

כדי לקבל אסימון OIDC לחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine, ב-App Engine או ב-Cloud Run, אתם יכולים להשתמש בדוגמת הקוד הבאה כדי ליצור אסימון לגישה למשאב שמאובטח באמצעות IAP:

C#

כדי לבצע אימות ב-IAP, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.


using Google.Apis.Auth.OAuth2;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

public class IAPClient
{
    /// <summary>
    /// Makes a request to a IAP secured application by first obtaining
    /// an OIDC token.
    /// </summary>
    /// <param name="iapClientId">The client ID observed on 
    /// https://console.cloud.google.com/apis/credentials. </param>
    /// <param name="uri">HTTP URI to fetch.</param>
    /// <param name="cancellationToken">The token to propagate operation cancel notifications.</param>
    /// <returns>The HTTP response message.</returns>
    public async Task<HttpResponseMessage> InvokeRequestAsync(
        string iapClientId, string uri, CancellationToken cancellationToken = default)
    {
        // Get the OidcToken.
        // You only need to do this once in your application
        // as long as you can keep a reference to the returned OidcToken.
        OidcToken oidcToken = await GetOidcTokenAsync(iapClientId, cancellationToken);

        // Before making an HTTP request, always obtain the string token from the OIDC token,
        // the OIDC token will refresh the string token if it expires.
        string token = await oidcToken.GetAccessTokenAsync(cancellationToken);

        // Include the OIDC token in an Authorization: Bearer header to 
        // IAP-secured resource
        // Note: Normally you would use an HttpClientFactory to build the httpClient.
        // For simplicity we are building the HttpClient directly.
        using HttpClient httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        return await httpClient.GetAsync(uri, cancellationToken);
    }

    /// <summary>
    /// Obtains an OIDC token for authentication an IAP request.
    /// </summary>
    /// <param name="iapClientId">The client ID observed on 
    /// https://console.cloud.google.com/apis/credentials. </param>
    /// <param name="cancellationToken">The token to propagate operation cancel notifications.</param>
    /// <returns>The HTTP response message.</returns>
    public async Task<OidcToken> GetOidcTokenAsync(string iapClientId, CancellationToken cancellationToken)
    {
        // Obtain the application default credentials.
        GoogleCredential credential = await GoogleCredential.GetApplicationDefaultAsync(cancellationToken);

        // Request an OIDC token for the Cloud IAP-secured client ID.
       return await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience(iapClientId), cancellationToken);
    }
}

Go

כדי לבצע אימות ב-IAP, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

import (
	"context"
	"fmt"
	"io"
	"net/http"

	"google.golang.org/api/idtoken"
)

// makeIAPRequest makes a request to an application protected by Identity-Aware
// Proxy with the given audience.
func makeIAPRequest(w io.Writer, request *http.Request, audience string) error {
	// request, err := http.NewRequest("GET", "http://example.com", nil)
	// audience := "IAP_CLIENT_ID.apps.googleusercontent.com"
	ctx := context.Background()

	// client is a http.Client that automatically adds an "Authorization" header
	// to any requests made.
	client, err := idtoken.NewClient(ctx, audience)
	if err != nil {
		return fmt.Errorf("idtoken.NewClient: %w", err)
	}

	response, err := client.Do(request)
	if err != nil {
		return fmt.Errorf("client.Do: %w", err)
	}
	defer response.Body.Close()
	if _, err := io.Copy(w, response.Body); err != nil {
		return fmt.Errorf("io.Copy: %w", err)
	}

	return nil
}

Java

כדי לבצע אימות ב-IAP, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.


import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.IdTokenCredentials;
import com.google.auth.oauth2.IdTokenProvider;
import com.google.common.base.Preconditions;
import java.io.IOException;
import java.util.Collections;

public class BuildIapRequest {
  private static final String IAM_SCOPE = "https://www.googleapis.com/auth/iam";

  private static final HttpTransport httpTransport = new NetHttpTransport();

  private BuildIapRequest() {}

  private static IdTokenProvider getIdTokenProvider() throws IOException {
    GoogleCredentials credentials =
        GoogleCredentials.getApplicationDefault().createScoped(Collections.singleton(IAM_SCOPE));

    Preconditions.checkNotNull(credentials, "Expected to load credentials");
    Preconditions.checkState(
        credentials instanceof IdTokenProvider,
        String.format(
            "Expected credentials that can provide id tokens, got %s instead",
            credentials.getClass().getName()));

    return (IdTokenProvider) credentials;
  }

  /**
   * Clone request and add an IAP Bearer Authorization header with ID Token.
   *
   * @param request Request to add authorization header
   * @param iapClientId OAuth 2.0 client ID for IAP protected resource
   * @return Clone of request with Bearer style authorization header with ID Token.
   * @throws IOException exception creating ID Token
   */
  public static HttpRequest buildIapRequest(HttpRequest request, String iapClientId)
      throws IOException {

    IdTokenProvider idTokenProvider = getIdTokenProvider();
    IdTokenCredentials credentials =
        IdTokenCredentials.newBuilder()
            .setIdTokenProvider(idTokenProvider)
            .setTargetAudience(iapClientId)
            .build();

    HttpRequestInitializer httpRequestInitializer = new HttpCredentialsAdapter(credentials);

    return httpTransport
        .createRequestFactory(httpRequestInitializer)
        .buildRequest(request.getRequestMethod(), request.getUrl(), request.getContent());
  }
}

Node.js

כדי לבצע אימות ב-IAP, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const url = 'https://some.iap.url';
// const targetAudience = 'IAP_CLIENT_ID.apps.googleusercontent.com';

const {GoogleAuth} = require('google-auth-library');
const auth = new GoogleAuth();

async function request() {
  console.info(`request IAP ${url} with target audience ${targetAudience}`);
  const client = await auth.getIdTokenClient(targetAudience);
  const res = await client.fetch(url);
  console.info(res.data);
}

request().catch(err => {
  console.error(err.message);
  process.exitCode = 1;
});

PHP

כדי לבצע אימות ב-IAP, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

namespace Google\Cloud\Samples\Iap;

# Imports Auth libraries and Guzzle HTTP libraries.
use Google\Auth\ApplicationDefaultCredentials;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;

/**
 * Make a request to an application protected by Identity-Aware Proxy.
 *
 * @param string $url The Identity-Aware Proxy-protected URL to fetch.
 * @param string $clientId The client ID used by Identity-Aware Proxy.
 */
function make_iap_request($url, $clientId)
{
    // create middleware, using the client ID as the target audience for IAP
    $middleware = ApplicationDefaultCredentials::getIdTokenMiddleware($clientId);
    $stack = HandlerStack::create();
    $stack->push($middleware);

    // create the HTTP client
    $client = new Client([
        'handler' => $stack,
        'auth' => 'google_auth'
    ]);

    // make the request
    $response = $client->get($url);
    print('Printing out response body:');
    print($response->getBody());
}

Python

כדי לבצע אימות ב-IAP, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests


def make_iap_request(url, client_id, method="GET", **kwargs):
    """Makes a request to an application protected by Identity-Aware Proxy.

    Args:
      url: The Identity-Aware Proxy-protected URL to fetch.
      client_id: The client ID used by Identity-Aware Proxy.
      method: The request method to use
              ('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
      **kwargs: Any of the parameters defined for the request function:
                https://github.com/requests/requests/blob/master/requests/api.py
                If no timeout is provided, it is set to 90 by default.

    Returns:
      The page body, or raises an exception if the page couldn't be retrieved.
    """
    # Set the default timeout, if missing
    if "timeout" not in kwargs:
        kwargs["timeout"] = 90

    # Obtain an OpenID Connect (OIDC) token from metadata server or using service
    # account.
    open_id_connect_token = id_token.fetch_id_token(Request(), client_id)

    # Fetch the Identity-Aware Proxy-protected URL, including an
    # Authorization header containing "Bearer " followed by a
    # Google-issued OpenID Connect token for the service account.
    resp = requests.request(
        method,
        url,
        headers={"Authorization": "Bearer {}".format(open_id_connect_token)},
        **kwargs
    )
    if resp.status_code == 403:
        raise Exception(
            "Service account does not have permission to "
            "access the IAP-protected application."
        )
    elif resp.status_code != 200:
        raise Exception(
            "Bad response from application: {!r} / {!r} / {!r}".format(
                resp.status_code, resp.headers, resp.text
            )
        )
    else:
        return resp.text

Ruby

כדי לבצע אימות ב-IAP, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

# url = "The Identity-Aware Proxy-protected URL to fetch"
# client_id = "The client ID used by Identity-Aware Proxy"
require "googleauth"
require "faraday"

# The client ID as the target audience for IAP
id_token_creds = Google::Auth::Credentials.default target_audience: client_id

headers = {}
id_token_creds.client.apply! headers

resp = Faraday.get url, nil, headers

if resp.status == 200
  puts "X-Goog-Iap-Jwt-Assertion:"
  puts resp.body
else
  puts "Error requesting IAP"
  puts resp.status
  puts resp.headers
end

קבלת אסימון OIDC מקובץ מפתח מקומי של חשבון שירות

כדי ליצור אסימון OIDC באמצעות קובץ מפתח של חשבון שירות, יוצרים טענת נכונוּת (assertion) של JWT וחותמים עליה באמצעות קובץ המפתח, ואז מחליפים את טענת הנכונוּת הזו בטוקן של מזהה. סקריפט Bash הבא מדגים את התהליך הזה:

Bash

#!/usr/bin/env bash
#
# Example script that generates an OIDC token using a service account key file and uses it to access an IAP-secured resource.

set -euo pipefail

get_token() {
  # Get the bearer token in exchange for the service account credentials
  local service_account_key_file_path="${1}"
  local iap_client_id="${2}"

  # Define the scope and token endpoint
  local iam_scope="https://www.googleapis.com/auth/iam"
  local oauth_token_uri="https://www.googleapis.com/oauth2/v4/token"

  # Extract data from service account key file
  local private_key_id="$(cat "${service_account_key_file_path}" | jq -r '.private_key_id')"
  local client_email="$(cat "${service_account_key_file_path}" | jq -r '.client_email')"
  local private_key="$(cat "${service_account_key_file_path}" | jq -r '.private_key')"

  # Set token timestamps (current time and expiration 10 minutes later)
  local issued_at="$(date +%s)"
  local expires_at="$((issued_at + 600))"

  # Create JWT header and payload
  local header="{'alg':'RS256','typ':'JWT','kid':'${private_key_id}'}"
  local header_base64="$(echo "${header}" | base64 | tr -d '\n')"
  local payload="{'iss':'${client_email}','aud':'${oauth_token_uri}','exp':${expires_at},'iat':${issued_at},'sub':'${client_email}','target_audience':'${iap_client_id}'}"
  local payload_base64="$(echo "${payload}" | base64 | tr -d '\n')"

  # Create JWT signature using the private key
  local signature_base64="$(printf %s "${header_base64}.${payload_base64}" | openssl dgst -binary -sha256 -sign <(printf '%s\n' "${private_key}")  | base64 | tr -d '\n')"
  local assertion="${header_base64}.${payload_base64}.${signature_base64}"

  # Exchange the signed JWT assertion for an ID token
  local token_payload="$(curl -s \
    --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
    --data-urlencode "assertion=${assertion}" \
    https://www.googleapis.com/oauth2/v4/token)"

  # Extract just the ID token from the response
  local bearer_id_token="$(echo "${token_payload}" | jq -r '.id_token')"
  echo "${bearer_id_token}"
}

main() {
  # Check if required arguments are provided
  if [[ $# -lt 3 ]]; then
    echo "Usage: $0 <service_account_key_file.json> <iap_client_id> <url>"
    exit 1
  fi

  # Assign parameters to variables
  SERVICE_ACCOUNT_KEY="$1"
  IAP_CLIENT_ID="$2"
  URL="$3"

  # Generate the ID token
  echo "Generating token..."
  ID_TOKEN=$(get_token "${SERVICE_ACCOUNT_KEY}" "${IAP_CLIENT_ID}")

  # Access the IAP-secured resource with the token
  echo "Accessing: ${URL}"
  curl --header "Authorization: Bearer ${ID_TOKEN}" "${URL}"
}

# Run the main function with all provided arguments
main "$@"

הסקריפט הזה מבצע את השלבים הבאים:

  1. חילוץ המידע על המפתח של חשבון השירות מקובץ המפתח בפורמט JSON
  2. יוצרת JWT עם השדות הנדרשים, כולל מזהה הלקוח של IAP בתור קהל היעד.
  3. חותמים על ה-JWT באמצעות המפתח הפרטי של חשבון השירות.
  4. מחליף את ה-JWT הזה באסימון OIDC דרך שירות OAuth של Google
  5. משתמש באסימון שנוצר כדי לשלוח בקשה מאומתת למשאב שמאובטח באמצעות IAP.

כדי להשתמש בסקריפט הזה:

  1. שומרים אותו בקובץ, לדוגמה: get_iap_token.sh
  2. הופכים אותו לקובץ הפעלה: chmod +x get_iap_token.sh
  3. מריצים אותה עם שלושה פרמטרים:
  ./get_iap_token.sh service-account-key.json \
    OAUTH_CLIENT_ID \
    URL

כאשר:

  • ‫service-account-key.json הוא קובץ המפתח של חשבון השירות שהורדתם
  • ‫OAUTH_CLIENT_ID הוא מזהה הלקוח ב-OAuth של המשאב שמאובטח באמצעות IAP
  • ‫URL היא כתובת ה-URL שאליה רוצים לגשת

קבלת אסימון OIDC באמצעות התחזות לחשבון שירות

בכל שאר המקרים, משתמשים ב-IAM credentials API כדי ליצור אסימון OIDC באמצעות התחזות לחשבון שירות של היעד, ממש לפני הגישה למשאב שמאובטח באמצעות IAP. התהליך כולל את השלבים הבאים:

  1. מקצים לחשבון השירות שמבצע את הקריאה (חשבון השירות שמשויך לקוד שמקבל את הטוקן של המזהה) את התפקיד "יצירת טוקנים מזהים מסוג OpenID Connect בחשבון שירות" (roles/iam.serviceAccountOpenIdTokenCreator).

    כך חשבון השירות שמבצע את הקריאה החוזרת יכול להתחזות לחשבון השירות המטורגט.

  2. משתמשים בפרטי הכניסה שסופקו על ידי חשבון השירות שמבצע את הקריאה, כדי להפעיל את ה-method‏ generateIdToken בחשבון השירות המטורגט.

    מגדירים את השדה audience למזהה הלקוח.

להוראות מפורטות, תוכלו לקרוא את המאמר יצירת טוקן של מזהה.

אימות מכותרת Proxy-Authorization

אם האפליקציה שלכם משתמשת בכותרת הבקשה Authorization, אתם יכולים לכלול את טוקן המזהה בכותרת Proxy-Authorization: Bearer במקום זאת. אם בכותרת Proxy-Authorization נמצא טוקן של מזהה תקין, IAP מאשר את הבקשה באמצעותו. אחרי אישור הבקשה, IAP מעביר את הכותרת Authorization לאפליקציה בלי לעבד את התוכן.

אם לא נמצא טוקן של מזהה תקין בכותרת Proxy-Authorization,‏ IAP ממשיך לעבד את הכותרת Authorization ומסיר את הכותרת Proxy-Authorization לפני העברת הבקשה לאפליקציה.

גישה לאפליקציה

כדי לגשת לאפליקציה באמצעות הכותרת Proxy-Authorization, מריצים את הפקודה הבאה:

curl --verbose --header 'Proxy-Authorization: Bearer SIGNED_JWT' URL

המאמרים הבאים