feat: Set default GCP Scope (#16)

* feat: Set default GCP Scope

Update the GCP credential configuration to include a default scope for GCP access. The default scope is set to `https://www.googleapis.com/auth/cloud-platform` as recommended by [GCP's Best Practice](https://cloud.google.com/compute/docs/access/service-accounts#scopes_best_practice). This allows controlling the service account's access by granting it IAM roles.
This commit is contained in:
Elim Tsiagbey authored and GitHub committed 2024-10-30 13:58:45 -04:00
1 parent a75b9bd310
commit 89c8ee2d6d
7 files changed
+75 -13

No files matched your search

+32 -8
View File
@@ -130,12 +130,36 @@ func GetCredentialsConfig(secrets *structpb.Struct, attrs *CredentialAttributes)
return nil, errors.InvalidArgumentError("Error in the secrets provided", badFields)
}
return &Config{
ProjectId: attrs.ProjectId,
ClientEmail: attrs.ClientEmail,
Zone: attrs.Zone,
PrivateKey: privateKey,
PrivateKeyId: privateKeyId,
TargetServiceAccountId: attrs.TargetServiceAccountId,
}, nil
cfgOpts := []Option{}
if privateKeyId != "" && privateKey != "" {
cfgOpts = append(cfgOpts,
WithPrivateKey(privateKey),
WithPrivateKeyId(privateKeyId))
}
if attrs.ProjectId != "" {
cfgOpts = append(cfgOpts, WithProjectId(attrs.ProjectId))
}
if attrs.ClientEmail != "" {
cfgOpts = append(cfgOpts, WithClientEmail(attrs.ClientEmail))
}
if attrs.Zone != "" {
cfgOpts = append(cfgOpts, WithZone(attrs.Zone))
}
if privateKey != "" {
cfgOpts = append(cfgOpts, WithPrivateKey(privateKey))
}
if privateKeyId != "" {
cfgOpts = append(cfgOpts, WithPrivateKeyId(privateKeyId))
}
if attrs.TargetServiceAccountId != "" {
cfgOpts = append(cfgOpts, WithTargetServiceAccountId(attrs.TargetServiceAccountId))
}
credentialsConfig, err := NewConfig(cfgOpts...)
if err != nil {
return nil, fmt.Errorf("error creating credentials config: %w", err)
}
return credentialsConfig, nil
}
+7 -1
View File
@@ -120,12 +120,15 @@ func TestGetCredentialsConfig(t *testing.T) {
},
expected: &Config{
Zone: "us-central-1a",
Scopes: []string{defaultGCPScope},
},
},
{
name: "nil attributes",
attrs: nil,
expected: &Config{},
expected: &Config{
Scopes: []string{defaultGCPScope},
},
},
{
name: "unknown fields in secrets",
@@ -156,6 +159,7 @@ func TestGetCredentialsConfig(t *testing.T) {
ClientEmail: "test@test.com",
PrivateKey: "test-private-key",
PrivateKeyId: "test-private-key-id",
Scopes: []string{defaultGCPScope},
},
},
{
@@ -221,6 +225,7 @@ func TestGetCredentialsConfig(t *testing.T) {
PrivateKey: "test-private-key",
PrivateKeyId: "test-private-key-id",
ClientEmail: "test@test.com",
Scopes: []string{defaultGCPScope},
},
},
{
@@ -242,6 +247,7 @@ func TestGetCredentialsConfig(t *testing.T) {
PrivateKeyId: "test-private-key-id",
ClientEmail: "test@test.com",
TargetServiceAccountId: "test-target-service-account",
Scopes: []string{defaultGCPScope},
},
},
}
+9 -1
View File
@@ -31,9 +31,17 @@ var findDefaultCredentialsFn = func(ctx context.Context, scopes ...string) (*goo
return google.FindDefaultCredentials(ctx, scopes...)
}
const (
// serviceAccountTokenLifetime is the lifetime of the generated GCP authentication token.
// The token is valid for 1 hour.
const serviceAccountTokenLifetime = time.Hour
serviceAccountTokenLifetime = time.Hour
// defaultGCPScope is the default scope for GCP.
// GCP requires the cloud-platform scope to access all GCP services.
// GCP recommends setting the scope to https://www.googleapis.com/auth/cloud-platform
// and then controlling the service account's access by granting it IAM roles.
// https://cloud.google.com/compute/docs/access/service-accounts#scopes_best_practice
defaultGCPScope = "https://www.googleapis.com/auth/cloud-platform"
)
// Config is the configuration for the GCP credential.
type Config struct {
+24 -1
View File
@@ -416,7 +416,9 @@ func TestNewConfig(t *testing.T) {
{
name: "No Options",
options: []Option{},
expected: &Config{},
expected: &Config{
Scopes: []string{defaultGCPScope},
},
expectError: false,
},
{
@@ -429,6 +431,27 @@ func TestNewConfig(t *testing.T) {
expected: nil,
expectError: true,
},
{
name: "no scope set",
options: []Option{
WithProjectId("test-project-id"),
WithPrivateKey("test-private-key"),
WithPrivateKeyId("test-private-key-id"),
WithClientEmail("test-email@example.com"),
WithTargetServiceAccountId("target-service-account@example.com"),
WithZone("test-zone"),
},
expected: &Config{
ProjectId: "test-project-id",
PrivateKey: "test-private-key",
PrivateKeyId: "test-private-key-id",
ClientEmail: "test-email@example.com",
TargetServiceAccountId: "target-service-account@example.com",
Zone: "test-zone",
Scopes: []string{defaultGCPScope},
},
expectError: false,
},
}
for _, tt := range tests {
+1
View File
@@ -37,6 +37,7 @@ type Option func(*Options) error
func getDefaultOptions() *Options {
return &Options{
WithCredentialsConfig: &Config{},
WithScopes: []string{defaultGCPScope},
}
}
+1 -1
View File
@@ -111,7 +111,7 @@ func Test_getOpts(t *testing.T) {
t.Run("WithScopes", func(t *testing.T) {
opts, err := getOpts()
require.NoError(t, err)
require.Nil(t, opts.WithScopes)
require.Equal(t, []string{defaultGCPScope}, opts.WithScopes)
scopes := []string{"test"}
opts, err = getOpts(WithScopes(scopes))
+1 -1
View File
@@ -26,7 +26,7 @@ boundary host-sets create plugin \
-host-catalog-id HOST_CATALOG_ID \
-name "Example Plugin-Based Host Set" \
-description "Description for plugin-based host set" \
-attr filters=status=RUNNING
-attr filters=status=RUNNING \
-attr filters=labels.env:prod
```