diff --git a/connection/aws.go b/connection/aws.go index 88380c9d..d40acd9a 100644 --- a/connection/aws.go +++ b/connection/aws.go @@ -1,18 +1,28 @@ package connection import ( + "crypto/tls" "fmt" + "net/http" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/credentials/stscreds" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/flanksource/duty/context" "github.com/flanksource/duty/types" + "github.com/henvic/httpretty" ) // +kubebuilder:object:generate=true type AWSConnection struct { // ConnectionName of the connection. It'll be used to populate the endpoint, accessKey and secretKey. ConnectionName string `yaml:"connection,omitempty" json:"connection,omitempty"` - AccessKey types.EnvVar `yaml:"accessKey" json:"accessKey,omitempty"` - SecretKey types.EnvVar `yaml:"secretKey" json:"secretKey,omitempty"` + AccessKey types.EnvVar `yaml:"accessKey,omitempty" json:"accessKey,omitempty"` + SecretKey types.EnvVar `yaml:"secretKey,omitempty" json:"secretKey,omitempty"` SessionToken types.EnvVar `yaml:"sessionToken,omitempty" json:"sessionToken,omitempty"` + AssumeRole string `yaml:"assumeRole,omitempty" json:"assumeRole,omitempty"` Region string `yaml:"region,omitempty" json:"region,omitempty"` Endpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty"` // Skip TLS verify when connecting to aws @@ -58,21 +68,27 @@ func (t *AWSConnection) Populate(ctx ConnectionContext) error { t.Region = region } } + + if t.AssumeRole == "" { + if role, ok := connection.Properties["assumeRole"]; ok { + t.AssumeRole = role + } + } } - if accessKey, err := ctx.GetEnvValueFromCache(t.AccessKey, ""); err != nil { + if accessKey, err := ctx.GetEnvValueFromCache(t.AccessKey, ctx.GetNamespace()); err != nil { return fmt.Errorf("could not parse AWS access key id: %v", err) } else { t.AccessKey.ValueStatic = accessKey } - if secretKey, err := ctx.GetEnvValueFromCache(t.SecretKey, ""); err != nil { + if secretKey, err := ctx.GetEnvValueFromCache(t.SecretKey, ctx.GetNamespace()); err != nil { return fmt.Errorf("could not parse AWS secret access key: %w", err) } else { t.SecretKey.ValueStatic = secretKey } - if sessionToken, err := ctx.GetEnvValueFromCache(t.SessionToken, ""); err != nil { + if sessionToken, err := ctx.GetEnvValueFromCache(t.SessionToken, ctx.GetNamespace()); err != nil { return fmt.Errorf("could not parse AWS session token: %w", err) } else { t.SessionToken.ValueStatic = sessionToken @@ -80,3 +96,47 @@ func (t *AWSConnection) Populate(ctx ConnectionContext) error { return nil } + +// Client returns a new aws config. +// Call this on a hydrated connection. +func (t *AWSConnection) Client(ctx context.Context) (aws.Config, error) { + var tr http.RoundTripper + tr = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: t.SkipTLSVerify}, + } + + if ctx.IsTrace() { + httplogger := &httpretty.Logger{ + Time: true, + TLS: ctx.Logger.IsLevelEnabled(7), + RequestHeader: true, + RequestBody: ctx.Logger.IsLevelEnabled(8), + ResponseHeader: true, + ResponseBody: ctx.Logger.IsLevelEnabled(9), + Colors: true, + Formatters: []httpretty.Formatter{&httpretty.JSONFormatter{}}, + } + + tr = httplogger.RoundTripper(tr) + } + + options := []func(*config.LoadOptions) error{ + config.WithRegion(t.Region), + config.WithHTTPClient(&http.Client{Transport: tr}), + } + + if !t.AccessKey.IsEmpty() { + options = append(options, config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(t.AccessKey.ValueStatic, t.SecretKey.ValueStatic, ""))) + } + + cfg, err := config.LoadDefaultConfig(ctx, options...) + if err != nil { + return aws.Config{}, err + } + + if t.AssumeRole != "" { + cfg.Credentials = aws.NewCredentialsCache(stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), t.AssumeRole)) + } + + return cfg, nil +} diff --git a/connection/connection.go b/connection/connection.go index d8edc693..4198a54d 100644 --- a/connection/connection.go +++ b/connection/connection.go @@ -11,4 +11,5 @@ type ConnectionContext interface { context.Context HydrateConnectionByURL(connectionName string) (*models.Connection, error) GetEnvValueFromCache(env types.EnvVar, namespace string) (string, error) + GetNamespace() string } diff --git a/go.mod b/go.mod index f50dfef7..aa73685d 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,10 @@ require ( github.com/RaveNoX/go-jsonmerge v1.0.0 github.com/WinterYukky/gorm-extra-clause-plugin v0.2.0 github.com/asecurityteam/rolling v2.0.4+incompatible + github.com/aws/aws-sdk-go-v2 v1.30.4 + github.com/aws/aws-sdk-go-v2/config v1.27.28 + github.com/aws/aws-sdk-go-v2/credentials v1.17.28 + github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 github.com/eko/gocache/lib/v4 v4.1.6 github.com/eko/gocache/store/go_cache/v4 v4.2.2 github.com/exaring/otelpgx v0.5.2 @@ -20,6 +24,7 @@ require ( github.com/google/gops v0.3.28 github.com/google/uuid v1.6.0 github.com/hashicorp/hcl/v2 v2.21.0 + github.com/henvic/httpretty v0.1.2 github.com/hexops/gotextdiff v1.0.3 github.com/invopop/jsonschema v0.12.0 github.com/itchyny/gojq v0.12.16 @@ -78,6 +83,15 @@ require ( github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/aws/aws-sdk-go v1.49.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect + github.com/aws/smithy-go v1.20.4 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect @@ -124,7 +138,6 @@ require ( github.com/hashicorp/go-getter v1.7.5 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect - github.com/henvic/httpretty v0.1.2 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/itchyny/timefmt-go v0.1.6 // indirect diff --git a/go.sum b/go.sum index 77594b1f..c2c469cb 100644 --- a/go.sum +++ b/go.sum @@ -676,6 +676,32 @@ github.com/asecurityteam/rolling v2.0.4+incompatible/go.mod h1:2D4ba5ZfYCWrIMleU github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.49.16 h1:KAQwhLg296hfffRdh+itA9p7Nx/3cXS/qOa3uF9ssig= github.com/aws/aws-sdk-go v1.49.16/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= +github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= +github.com/aws/aws-sdk-go-v2/config v1.27.28 h1:OTxWGW/91C61QlneCtnD62NLb4W616/NM1jA8LhJqbg= +github.com/aws/aws-sdk-go-v2/config v1.27.28/go.mod h1:uzVRVtJSU5EFv6Fu82AoVFKozJi2ZCY6WRCXj06rbvs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.28 h1:m8+AHY/ND8CMHJnPoH7PJIRakWGa4gbfbxuY9TGTUXM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.28/go.mod h1:6TF7dSc78ehD1SL6KpRIPKMA1GyyWflIkjqg+qmf4+c= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 h1:iAckBT2OeEK/kBDyN/jDtpEExhjeeA/Im2q4X0rJZT8= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.4/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= +github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= +github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=