Skip to content

Commit

Permalink
Added support for access tokens in gcpkms
Browse files Browse the repository at this point in the history
Signed-off-by: Christoffer Eide <[email protected]>
  • Loading branch information
christoffer-eide committed Nov 25, 2023
1 parent 418ea23 commit 26f3545
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 20 deletions.
24 changes: 18 additions & 6 deletions gcpkms/keysource.go
Expand Up @@ -3,7 +3,9 @@ package gcpkms // import "github.com/getsops/sops/v3/gcpkms"
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"golang.org/x/oauth2"
"os"
"regexp"
"strings"
Expand Down Expand Up @@ -208,16 +210,26 @@ func (key *MasterKey) newKMSClient() (*kms.KeyManagementClient, error) {
}

var opts []option.ClientOption
switch {
case key.credentialJSON != nil:
opts = append(opts, option.WithCredentialsJSON(key.credentialJSON))
default:
credentialJSON := key.credentialJSON

if credentialJSON == nil {
credentials, err := getGoogleCredentials()
if err != nil {
return nil, err
}
if credentials != nil {
opts = append(opts, option.WithCredentialsJSON(credentials))

credentialJSON = credentials
}

if credentialJSON != nil {
token := oauth2.Token{}

if err := json.Unmarshal(credentialJSON, &token); err != nil {
return nil, err
} else if token.AccessToken != "" {
opts = append(opts, option.WithTokenSource(oauth2.StaticTokenSource(&token)))
} else {
opts = append(opts, option.WithCredentialsJSON(credentialJSON))
}
}
if key.grpcConn != nil {
Expand Down
87 changes: 74 additions & 13 deletions gcpkms/keysource_test.go
Expand Up @@ -3,7 +3,9 @@ package gcpkms
import (
"encoding/base64"
"fmt"
"io"
"net"
"os"
"testing"
"time"

Expand Down Expand Up @@ -118,34 +120,93 @@ func TestMasterKey_ToMap(t *testing.T) {

func TestMasterKey_createCloudKMSService(t *testing.T) {
tests := []struct {
key MasterKey
errString string
key MasterKey
credentials string
errString string
description string
}{
{
key: MasterKey{
ResourceID: "/projects",
credentialJSON: []byte("some secret"),
ResourceID: "/projects",
},
errString: "no valid resource ID",
credentials: "some secret",
errString: "no valid resource ID",
description: "invalid resource ID",
},
{
key: MasterKey{
ResourceID: testResourceID,
credentialJSON: []byte(`{ "client_id": "<client-id>.apps.googleusercontent.com",
},
credentials: `{ "client_id": "<client-id>.apps.googleusercontent.com",
"client_secret": "<secret>",
"type": "authorized_user"}`),
"type": "authorized_user"}`,
description: "valid user credentials",
},
{
key: MasterKey{
ResourceID: testResourceID,
},
credentials: `{ "access_token": "access_token"}`,
description: "valid access token credentials",
},
{
key: MasterKey{
ResourceID: testResourceID,
},
credentials: `{ invalid_json }`,
errString: "invalid character 'i' looking for beginning of object key string",
description: "invalid json",
},
{
key: MasterKey{
ResourceID: testResourceID,
},
credentials: `{}`,
errString: "missing 'type' field in credentials",
description: "invalid credentials",
},
}

for _, tt := range tests {
_, err := tt.key.newKMSClient()
if tt.errString != "" {
assert.Error(t, err)
assert.ErrorContains(t, err, tt.errString)
return
r := func(t *testing.T) {
_, err := tt.key.newKMSClient()
if tt.errString != "" {
assert.Error(t, err)
assert.ErrorContains(t, err, tt.errString)
return
}
assert.NoError(t, err)
}
assert.NoError(t, err)

t.Run(tt.description+" credentials from var", func(t *testing.T) {
tt.key.credentialJSON = []byte(tt.credentials)
r(t)
})

t.Run(tt.description+" credentials from env json", func(t *testing.T) {
t.Setenv("GOOGLE_CREDENTIALS", tt.credentials)
tt.key.credentialJSON = nil
r(t)
})

t.Run(tt.description+" credentials from env file", func(t *testing.T) {
file, err := os.CreateTemp(t.TempDir(), "gcp_creds.*.json")
assert.NoError(t, err)

_, err = io.WriteString(file, tt.credentials)
assert.NoError(t, err)

t.Setenv("GOOGLE_CREDENTIALS", file.Name())
tt.key.credentialJSON = nil
r(t)

// Test file permissions
err = os.Chmod(file.Name(), 200)
assert.NoError(t, err)

_, err = tt.key.newKMSClient()
assert.Error(t, err)
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -35,6 +35,7 @@ require (
github.com/stretchr/testify v1.8.4
github.com/urfave/cli v1.22.14
golang.org/x/net v0.18.0
golang.org/x/oauth2 v0.13.0
golang.org/x/sys v0.14.0
golang.org/x/term v0.14.0
google.golang.org/api v0.151.0
Expand Down Expand Up @@ -117,7 +118,6 @@ require (
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
Expand Down

0 comments on commit 26f3545

Please sign in to comment.