Files
threshold-plugin-gcp/internal/credential/attributes.go
T

168 lines
6.0 KiB
Go
Raw Normal View History

// Copyright IBM Corp. 2024, 2026
2024-04-02 15:47:49 -04:00
// SPDX-License-Identifier: MPL-2.0
package credential
import (
"fmt"
"repo.anhonesthost.net/CyberCoveLLC/threshold-plugin-gcp/internal/errors"
"repo.anhonesthost.net/CyberCoveLLC/threshold-plugin-gcp/internal/values"
2024-04-02 15:47:49 -04:00
"google.golang.org/protobuf/types/known/structpb"
)
2024-09-17 10:50:10 -04:00
// CredentialAttributes contain attributes used for authenticating to GCP
2024-08-06 11:51:00 -04:00
// and accessing a list of instances
2024-04-02 15:47:49 -04:00
type CredentialAttributes struct {
2024-09-17 10:50:10 -04:00
// ProjectId is the project id associated with the GCP credentials
ProjectId string
// Zone is the zone associated with the GCP credentials
Zone string
// DisableCredentialRotation disables the rotation of GCP service account key associated with the plugin
DisableCredentialRotation bool
// ClientEmail is the email associated with the GCP cloud credentials
ClientEmail string
// TargetServiceAccount is the unique identifier for the service account that will be impersonated
TargetServiceAccountId string
2024-04-02 15:47:49 -04:00
}
2024-09-17 10:50:10 -04:00
// GetCredentialAttributes checks attributes required by GCP to access
2024-08-06 11:51:00 -04:00
// a list of instances and populate them into Boundary's host catalog
2024-04-02 15:47:49 -04:00
func GetCredentialAttributes(in *structpb.Struct) (*CredentialAttributes, error) {
badFields := make(map[string]string)
2024-09-17 10:50:10 -04:00
projectId, err := values.GetStringValue(in, ConstProjectId, true)
2024-04-02 15:47:49 -04:00
if err != nil {
2024-09-17 10:50:10 -04:00
badFields[fmt.Sprintf("attributes.%s", ConstProjectId)] = err.Error()
2024-04-02 15:47:49 -04:00
}
zone, err := values.GetStringValue(in, ConstZone, true)
if err != nil {
badFields[fmt.Sprintf("attributes.%s", ConstZone)] = err.Error()
}
2024-09-17 10:50:10 -04:00
disableCredentialRotation, err := values.GetBoolValue(in, ConstDisableCredentialRotation, false)
if err != nil {
badFields[fmt.Sprintf("attributes.%s", ConstDisableCredentialRotation)] = err.Error()
}
clientEmail, err := values.GetStringValue(in, ConstClientEmail, false)
if err != nil {
badFields[fmt.Sprintf("attributes.%s", ConstClientEmail)] = err.Error()
}
targetServiceAccountId, err := values.GetStringValue(in, ConstTargetServiceAccountID, false)
if err != nil {
badFields[fmt.Sprintf("attributes.%s", ConstTargetServiceAccountID)] = err.Error()
}
2024-04-02 15:47:49 -04:00
if len(badFields) > 0 {
return nil, errors.InvalidArgumentError("Error in the attributes provider", badFields)
}
return &CredentialAttributes{
2024-09-17 10:50:10 -04:00
ProjectId: projectId,
Zone: zone,
DisableCredentialRotation: disableCredentialRotation,
ClientEmail: clientEmail,
TargetServiceAccountId: targetServiceAccountId,
2024-04-02 15:47:49 -04:00
}, nil
}
2024-10-21 10:47:06 -04:00
// GetCredentialsConfig parses values out of a protobuf struct secrets and returns a
// Config used for configuring an GCP session. An status error is returned
// with an InvalidArgument code if any unrecognized fields are found in the protobuf
// struct input.
func GetCredentialsConfig(secrets *structpb.Struct, attrs *CredentialAttributes) (*Config, error) {
// initialize secrets if it is nil
// secrets can be nil if the authentication type is Application Default Credential(ADC)
if secrets == nil {
secrets = &structpb.Struct{
Fields: make(map[string]*structpb.Value),
}
}
// initialize attrs if it is nil
// attributes can be nil if the authentication type is Application Default Credential(ADC)
// where the credentials are inferred from the environment and no fields are provided
// https://cloud.google.com/docs/authentication/application-default-credentials
if attrs == nil {
attrs = &CredentialAttributes{}
}
unknownFields := values.StructFields(secrets)
badFields := make(map[string]string)
privateKeyId, err := values.GetStringValue(secrets, ConstPrivateKeyId, false)
if err != nil {
badFields[fmt.Sprintf("secrets.%s", ConstPrivateKeyId)] = err.Error()
}
delete(unknownFields, ConstPrivateKeyId)
privateKey, err := values.GetStringValue(secrets, ConstPrivateKey, false)
if err != nil {
badFields[fmt.Sprintf("secrets.%s", ConstPrivateKey)] = err.Error()
}
delete(unknownFields, ConstPrivateKey)
delete(unknownFields, ConstCredsLastRotatedTime)
for s := range unknownFields {
badFields[fmt.Sprintf("secrets.%s", s)] = "unrecognized field"
}
switch {
2024-11-20 10:22:21 -05:00
// service account impersonation authentication requires the target service account id and client_email
case attrs.TargetServiceAccountId != "" && attrs.ClientEmail == "":
2024-10-21 10:47:06 -04:00
badFields[fmt.Sprintf("secrets.%s", ConstPrivateKey)] = "must not be empty when target service account id is set"
2024-11-20 10:22:21 -05:00
// service account impersonation authentication requires the target service account id and private key
case attrs.TargetServiceAccountId != "" && privateKey == "":
2024-10-21 10:47:06 -04:00
badFields[fmt.Sprintf("attributes.%s", ConstClientEmail)] = "must not be empty when target service account id is set"
2024-11-20 10:22:21 -05:00
// service account key credentials requires the private key and client email
2024-10-21 10:47:06 -04:00
case privateKey != "" && attrs.ClientEmail == "":
badFields[fmt.Sprintf("attributes.%s", ConstClientEmail)] = "must not be empty when private key is set"
2024-11-20 10:22:21 -05:00
// service account key credentials requires the client_email
2024-10-21 10:47:06 -04:00
case attrs.ClientEmail != "" && privateKey == "":
badFields[fmt.Sprintf("secrets.%s", ConstPrivateKey)] = "must not be empty when client email is set"
}
if len(badFields) > 0 {
return nil, errors.InvalidArgumentError("Error in the secrets provided", badFields)
}
2024-10-30 13:58:45 -04:00
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
2024-10-21 10:47:06 -04:00
}