Skip to content

Commit

Permalink
migrate to using jwtaccesstoken with scope only
Browse files Browse the repository at this point in the history
Signed-off-by: sal rashid <[email protected]>
  • Loading branch information
salrashid123 committed Sep 5, 2024
1 parent ed63b53 commit ae22aa4
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 111 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ Implementations of various [TokenSource](https://godoc.org/golang.org/x/oauth2#T
for a simple end-to-end, see [Trusted Platform Module (TPM) based GCP Service Account Key](https://gist.github.com/salrashid123/865ea715881cb7c020da987b08c3881a)


There are two types of tokens this TokenSource fulfills:
The types of tokens this TokenSource fulfills:

- `JWTAccessToken`
- `Oauth2 access_tokens`.
- [Self-signed JWT with Scopes](https://google.aip.dev/auth/4111)


### Usage
Expand Down Expand Up @@ -210,7 +209,8 @@ note, there are also several ways to securely transfer public/private keys betwe
The TPM based `TokenSource` can now be used to access a GCP resource using either a plain HTTPClient or _native_ GCP library (`google-cloud-pubsub`)!!

```bash
go run main.go --projectId=core-eso \
cd example/tpm/
go run no_policy/main.go --projectId=core-eso \
--persistentHandle=0x81010002 \
--serviceAccountEmail="[email protected]" \
--bucketName=core-eso-bucket --keyId=71b831d149e4667809644840cda2e7e0080035d5
Expand All @@ -237,7 +237,6 @@ eg
Name: pub.Name,
},
Email: *serviceAccountEmail,
UseOauthToken: true,
})

// use it with a gcp api client
Expand Down
13 changes: 5 additions & 8 deletions example/tpm/no_policy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,10 @@ func main() {
// Name: pub.Name,
// },
// Email: *serviceAccountEmail,
// UseOauthToken: true,
// })

// log.Printf("======= oauth2 end using persistent handle ========")
//
log.Printf("======= oauth2 end using persistent handle ========")

pub, err := tpm2.ReadPublic{
ObjectHandle: tpm2.TPMHandle(*persistentHandle), //persistent handle
}.Execute(rwr)
Expand All @@ -182,8 +181,7 @@ func main() {
Handle: tpm2.TPMHandle(*persistentHandle), // persistent handle
Name: pub.Name,
},
Email: *serviceAccountEmail,
UseOauthToken: true,
Email: *serviceAccountEmail,
})
if err != nil {
log.Fatal(err)
Expand All @@ -199,21 +197,20 @@ func main() {

ctx := context.Background()

// GCS does not support JWTAccessTokens, the following will only work if UseOauthToken is set to True
storageClient, err := storage.NewClient(ctx, option.WithTokenSource(ts))
if err != nil {
log.Fatal(err)
}
sit := storageClient.Buckets(ctx, *projectId)
for {
_, err := sit.Next()
battrs, err := sit.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatal(err)
}
//log.Printf(battrs.Name)
log.Printf(battrs.Name)
}
i = i + 1
log.Printf("%d\n", i)
Expand Down
5 changes: 2 additions & 3 deletions example/tpm/password_policy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,8 @@ func main() {
Handle: tpm2.TPMHandle(*persistentHandle), // persistent handle
Name: pub.Name,
},
AuthSession: se,
Email: *serviceAccountEmail,
UseOauthToken: true,
AuthSession: se,
Email: *serviceAccountEmail,
})
if err != nil {
log.Fatal(err)
Expand Down
5 changes: 2 additions & 3 deletions example/tpm/pcr_policy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,8 @@ func main() {
Handle: tpm2.TPMHandle(*persistentHandle), // persistent handle
Name: pub.Name,
},
AuthSession: p,
Email: *serviceAccountEmail,
UseOauthToken: true,
AuthSession: p,
Email: *serviceAccountEmail,
})
if err != nil {
log.Fatal(err)
Expand Down
108 changes: 16 additions & 92 deletions tpm/tpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@
package google

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"sync"
"time"
Expand All @@ -29,12 +25,11 @@ const (
// TpmTokenConfig parameters to start Credential based off of TPM RSA Private Key.
type TpmTokenConfig struct {
TPMDevice io.ReadWriteCloser
Email, Audience string
Email string
NamedHandle tpm2.NamedHandle // load a key from handle
AuthSession tpmjwt.Session
KeyId string
Scopes []string
UseOauthToken bool
EncryptionHandle tpm2.TPMHandle // (optional) handle to use for transit encryption
EncryptionPub *tpm2.TPMTPublic // (optional) public key to use for transit encryption

Expand All @@ -43,13 +38,12 @@ type TpmTokenConfig struct {
type tpmTokenSource struct {
refreshMutex *sync.Mutex
oauth2.TokenSource
email, audience string
email string
tpmdevice io.ReadWriteCloser
namedHandle tpm2.NamedHandle
authSession tpmjwt.Session
keyId string
scopes []string
useOauthToken bool
myToken *oauth2.Token
encryptionHandle tpm2.TPMHandle // (optional) handle to use for transit encryption
encryptionPub *tpm2.TPMTPublic // (optional) public key to use for transit encryption
Expand Down Expand Up @@ -88,9 +82,6 @@ type ClaimWithSubject struct {
// This field is optional but recomended if UseOauthTOken is false
// Find the keyId associated with the service account by running:
// `gcloud iam service-accounts keys list --iam-account=<email>``
// UseOauthToken (bool): Use oauth2 access_token (true) or JWTAccessToken (false)
// see: https://developers.google.com/identity/protocols/oauth2/service-account#jwt-auth
// eg: audience="https://pubsub.googleapis.com/google.pubsub.v1.Publisher"
func TpmTokenSource(tokenConfig *TpmTokenConfig) (oauth2.TokenSource, error) {

if &tokenConfig.NamedHandle == nil || tokenConfig.TPMDevice == nil {
Expand All @@ -101,23 +92,17 @@ func TpmTokenSource(tokenConfig *TpmTokenConfig) (oauth2.TokenSource, error) {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: TPMTokenConfig.Email and cannot be nil")
}

if tokenConfig.Audience == "" && tokenConfig.UseOauthToken == false {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: Audience must be specified if UseOauthToken is false")
}

if len(tokenConfig.Scopes) == 0 {
tokenConfig.Scopes = []string{GCP_CLOUD_PLATFORM_SCOPE}
}

return &tpmTokenSource{
refreshMutex: &sync.Mutex{},
email: tokenConfig.Email,
audience: tokenConfig.Audience,
tpmdevice: tokenConfig.TPMDevice,
authSession: tokenConfig.AuthSession,
keyId: tokenConfig.KeyId,
scopes: tokenConfig.Scopes,
useOauthToken: tokenConfig.UseOauthToken,
namedHandle: tokenConfig.NamedHandle,
encryptionHandle: tokenConfig.EncryptionHandle,
encryptionPub: tokenConfig.EncryptionPub,
Expand Down Expand Up @@ -154,89 +139,28 @@ func (ts *tpmTokenSource) Token() (*oauth2.Token, error) {
exp := iat.Add(time.Hour)
msg := ""

if ts.useOauthToken {

claims := &ClaimWithSubject{
Scope: strings.Join(ts.scopes, " "),
RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(iat),
ExpiresAt: jwt.NewNumericDate(exp),
Issuer: ts.email,
Audience: []string{"https://oauth2.googleapis.com/token"},
},
}

token := jwt.NewWithClaims(tpmjwt.SigningMethodTPMRS256, claims)

if ts.keyId != "" {
token.Header["kid"] = ts.keyId
}

tokenString, err := token.SignedString(keyctx)
if err != nil {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: unable to POST token request, %v", err)
}

client := &http.Client{}

data := url.Values{}
data.Set("grant_type", "assertion")
data.Add("assertion_type", "http://oauth.net/grant_type/jwt/1.0/bearer")
data.Add("assertion", tokenString)

hreq, err := http.NewRequest(http.MethodPost, "https://accounts.google.com/o/oauth2/token", bytes.NewBufferString(data.Encode()))
if err != nil {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: Unable to generate token Request, %v", err)
}
hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
resp, err := client.Do(hreq)
if err != nil {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: unable to POST token request, %v", err)
}

if resp.StatusCode != http.StatusOK {
f, err := io.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: unable to POST token request %v", err)
}
return nil, fmt.Errorf("salrashid123/x/oauth2/google: Token Request error:, %s", string(f))
}

f, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: unable to parse tokenresponse, %v", err)
}
resp.Body.Close()
var m rtokenJSON
err = json.Unmarshal(f, &m)
if err != nil {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: Unable to unmarshal response, %v", err)
}
msg = m.AccessToken

} else {

claims := &jwt.RegisteredClaims{
claims := &ClaimWithSubject{
Scope: strings.Join(ts.scopes, " "),
RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(iat),
ExpiresAt: jwt.NewNumericDate(exp),
Issuer: ts.email,
Subject: ts.email,
Audience: []string{ts.audience},
}
},
}

token := jwt.NewWithClaims(tpmjwt.SigningMethodTPMRS256, claims)
token := jwt.NewWithClaims(tpmjwt.SigningMethodTPMRS256, claims)

if ts.keyId != "" {
token.Header["kid"] = ts.keyId
}
if ts.keyId != "" {
token.Header["kid"] = ts.keyId
}

tokenString, err := token.SignedString(keyctx)
if err != nil {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: unable to POST token request, %v", err)
}
msg = tokenString
tokenString, err := token.SignedString(keyctx)
if err != nil {
return nil, fmt.Errorf("salrashid123/x/oauth2/google: unable to POST token request, %v", err)
}
msg = tokenString

ts.myToken = &oauth2.Token{AccessToken: msg, TokenType: "Bearer", Expiry: exp}
return ts.myToken, nil
}

0 comments on commit ae22aa4

Please sign in to comment.