googleiapclient

package
v0.0.0-...-796d9c6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 25, 2023 License: BSD-2-Clause Imports: 15 Imported by: 0

Documentation

Overview

Package googleiapclient provides a programmatic way to use a service account to access resources protected by Google Cloud Platform's Identity Aware Proxy product.

See Also

https://cloud.google.com/iap/docs/authentication-howto https://gist.github.com/plmrry/f78136bba68f810622bc2840497ef7e1

Usage

1. Create a service account in the GCP console and download credentials in JSON format (the P12 option does not work).

2. Encode the json file you downloaded and place in an environment variable:

export GOOGLE_CREDS="$(cat rchapman-f9bcc275ce03.json | base64)"

3. Get your OAuth client ID, which can be found at GCP Console > Security > Identity Aware Proxy, click three dots beside your load balancer, Edit OAuth Client, Client ID

You can also curl a IAP protected endpoint and look at the redirect to find the client ID:

$ curl -v https://test.initech.com/nonexist
> GET /nonexist HTTP/1.1
[...]

< HTTP/1.1 302 Found
[...]
< Location: https://accounts.google.com/o/oauth2/v2/auth?client_id=823926513327-pr0714rqtdb223bahl0nq2jcd4ur79ec.apps.googleusercontent.com&response_type=code&scope=openid+email&redirect_uri=https://test.initech.com/_gcp_gatekeeper/authenticate&state=XXXXXXX
< X-Goog-IAP-Generated-Response: true
< Content-Length: 0
[...]

4. Add code to your program to use the library. In this example, GOOGLE_CREDS is the environment variable which contains the base64 encoded service account credentials in json format. The first parameter to JWTToken() is the OAuth client ID you found in step #3. The OAuth client ID will be encoded as target_audience before it is sent to the Google OAuth service to obtain a JWT token.

import (
       "github.com/ryanchapman/googleiapclient"
)

func main() {
        // get service account from environment variable   GOOGLE_CREDS
        iapClient := googleiapclient.NewIAPClient("GOOGLE_CREDS")
        requestedExpiration := time.Duration(1 * time.Hour) // Google's OAuth service may change this
        token, err := iapClient.JWTToken("823926513327-pr0714rqtdb223bahl0nq2jcd4ur79ec.apps.googleusercontent.com", requestedExpiration)
        if err != nil {
                log.Panicf("Could not get JWT token: %+v", err)
        }

        fmt.Printf("%s\n", token)

        url := "https://test.initech.com"
        req, err := http.NewRequest("GET", url, nil)
        if err != nil {
                log.Panicf("Could not create GET request to %s: %+v", url, err)
        }

        req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
        client := http.Client{}
        resp, err := client.Do(req)
        if resp != nil {
                defer resp.Body.Close()
        }
        // handle response
        // ...

        iapClient.Done() // stops automatic updating of tokens in the background
}

Index

Constants

View Source
const TOKEN_URL = "https://www.googleapis.com/oauth2/v4/token"

Variables

This section is empty.

Functions

func CalculateTokenExpiry

func CalculateTokenExpiry(jwtToken string) (tokenExpiration time.Time, err error)

Utility function which, given a JWT string, returns the token expiration time from the "exp" claim.

Types

type IAPClient

type IAPClient struct {
	// contains filtered or unexported fields
}

func NewIAPClient

func NewIAPClient(envVarName string, requestedTokenExpiry time.Duration) *IAPClient

Create a new IAPClient with credentials that are base64 encoded in an environment variable named envVarName and a requested expiration (Google's OAuth service may or may not honor your requested expiration).

IAPClient will automatically renew tokens as needed. Call JWTToken() right before you need to use it.

For example, if you have a service account file from GCP named proj.adf102a21567.json:

export GOOGLE_CREDS="$(cat proj.adf102a21567.json | base64)"
./goprogramUsingThisLibrary

in program code:

requestedExpiration := time.Duration(1 * time.Hour)
iapClient := NewIAPClient("GOOGLE_CREDS", requestedExpiration)

func (*IAPClient) BackgroundTokenRefreshRunning

func (i *IAPClient) BackgroundTokenRefreshRunning() bool

Return if the background JWT token refresh is currently running

func (*IAPClient) CurrentJWTTokenExpiration

func (i *IAPClient) CurrentJWTTokenExpiration() time.Time

Return when the current JWT token will expire

func (*IAPClient) Done

func (i *IAPClient) Done()

Call Done() to stop automatic updating of tokens (usually before you delete an IAPClient struct)

func (*IAPClient) JWTToken

func (i *IAPClient) JWTToken(targetAudience string) (jwtToken string, err error)

Generate a JWT bearer token that can be passed to a IAP protected endpoint which has the specified target audience (OAuth Client ID).

You can find the target audience by going to GCP Console > Security > Identity Aware Proxy, click three dots beside your load balancer, Edit OAuth Client, Client ID

It will look something like

"823926513327-pr0714rqtdb223bahl0nq2jcd4ur79ec.apps.googleusercontent.com"

(without http:// or https://)

Another method which works as of this writing is to curl a IAP protected endpoint and look at the redirect:

$ curl -v https://test.initech.com/nonexist
> GET /nonexist HTTP/1.1
[...]

< HTTP/1.1 302 Found
[...]
< Location: https://accounts.google.com/o/oauth2/v2/auth?client_id=823926513327-pr0714rqtdb223bahl0nq2jcd4ur79ec.apps.googleusercontent.com&response_type=code&scope=openid+email&redirect_uri=https://test.initech.com/_gcp_gatekeeper/authenticate&state=XXXXXXX
< X-Goog-IAP-Generated-Response: true
< Content-Length: 0
[...]

The returned JWT token is good for a period of time. You can call JWTToken() again later to get the current token. googleiapclient will automatically refresh tokens in the background. Expiration is encoded in the JWT that is returned.

Once you have the JWT token, you can make requests to the IAP protected endpoint by passing the JWT as a bearer token. For example:

iapClient := NewIAPClient("GOOGLE_CREDS")
token, err := iapClient.JWTToken("823926513327-pr0714rqtdb223bahl0nq2jcd4ur79ec.apps.googleusercontent.com")
if err != nil {
        log.Panicf("Could not get JWT token: %+v", err)
}

url := "https://test.initech.com"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
        log.Panicf("Could not create GET request to %s: %+v", url, err)
}

req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)
client := http.Client{}
resp, err := client.Do(req)
if resp != nil {
        defer resp.Body.Close()
}
/* handle response */

// stop automatic updating of tokens in the background
iapClient.Done()

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL