Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow IAM role credentials #5

Merged
merged 7 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,31 @@ region = "eu-central-1"
subnet_id = "sample_subnet_id"

[credentials]
# Allowed values are: static, role
# When using IAM roles, you can omit the [credentials.static] section
credential_type = "static"
[credentials.static]
access_key_id = "sample_access_key_id"
secret_access_key = "sample_secret_access_key"
session_token = "sample_session_token"
```

If you're running GARM on eks, you can use the IAM role assigned to the eks nodes by setting `credential_type` to `role`. In order for this to work, the environment variables prefixed with `AWS_` need to be visible by the provider. By default, GARM does not pass through any environment variables to the external providers. It only sets the needed variables that controls the operations of the provider itself. To pass through variables, you will need to set the `environment_variables` option in the provider configuration. For example:

```toml
[[provider]]
name = "ec2_external"
description = "external provider for AWS"
provider_type = "external"
disable_jit_config = false
[provider.external]
config_file = "/etc/garm/garm-provider-aws.toml"
provider_executable = "/opt/garm/providers/garm-provider-aws"
# This option will pass all environment variables that start with AWS_ to the provider.
# To pass in individual variables, you can add the entire name to the list.
environment_variables = ["AWS_"]
```

## Creating a pool

After you [add it to garm as an external provider](https://github.com/cloudbase/garm/blob/main/doc/providers.md#the-external-provider), you need to create a pool that uses it. Assuming you named your external provider as ```aws``` in the garm config, the following command should create a new pool:
Expand Down
54 changes: 44 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ import (
"github.com/aws/aws-sdk-go-v2/credentials"
)

type AWSCredentialType string

const (
AWSCredentialTypeStatic AWSCredentialType = "static"
AWSCredentialTypeRole AWSCredentialType = "role"
)

// NewConfig returns a new Config
func NewConfig(cfgFile string) (*Config, error) {
var config Config
Expand Down Expand Up @@ -59,7 +66,7 @@ func (c *Config) Validate() error {
return nil
}

type Credentials struct {
type StaticCredentials struct {
// AWS Access key ID
AccessKeyID string `toml:"access_key_id"`

Expand All @@ -70,7 +77,7 @@ type Credentials struct {
SessionToken string `toml:"session_token"`
}

func (c Credentials) Validate() error {
func (c StaticCredentials) Validate() error {
if c.AccessKeyID == "" {
return fmt.Errorf("missing access_key_id")
}
Expand All @@ -85,19 +92,46 @@ func (c Credentials) Validate() error {
return nil
}

type Credentials struct {
CredentialType AWSCredentialType `toml:"credential_type"`
StaticCredentials StaticCredentials `toml:"static"`
}

func (c Credentials) Validate() error {
switch c.CredentialType {
case AWSCredentialTypeStatic:
return c.StaticCredentials.Validate()
case AWSCredentialTypeRole:
case "":
return fmt.Errorf("missing credential_type")
default:
return fmt.Errorf("unknown credential type: %s", c.CredentialType)
}
return nil
}

func (c Config) GetAWSConfig(ctx context.Context) (aws.Config, error) {
if err := c.Credentials.Validate(); err != nil {
return aws.Config{}, fmt.Errorf("failed to validate credentials: %w", err)
}

cfg, err := config.LoadDefaultConfig(ctx,
config.WithCredentialsProvider(
credentials.NewStaticCredentialsProvider(
c.Credentials.AccessKeyID,
c.Credentials.SecretAccessKey,
c.Credentials.SessionToken)),
config.WithRegion(c.Region),
)
var cfg aws.Config
var err error
switch c.Credentials.CredentialType {
case AWSCredentialTypeStatic:
cfg, err = config.LoadDefaultConfig(ctx,
config.WithCredentialsProvider(
credentials.NewStaticCredentialsProvider(
c.Credentials.StaticCredentials.AccessKeyID,
c.Credentials.StaticCredentials.SecretAccessKey,
c.Credentials.StaticCredentials.SessionToken)),
config.WithRegion(c.Region),
)
case AWSCredentialTypeRole:
cfg, err = config.LoadDefaultConfig(ctx, config.WithRegion(c.Region))
default:
return aws.Config{}, fmt.Errorf("unknown credential type: %s", c.Credentials.CredentialType)
}
if err != nil {
return aws.Config{}, fmt.Errorf("failed to get aws config: %w", err)
}
Expand Down
89 changes: 63 additions & 26 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ func TestConfigValidate(t *testing.T) {
name: "valid config",
c: &Config{
Credentials: Credentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
CredentialType: AWSCredentialTypeStatic,
StaticCredentials: StaticCredentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
},
},
SubnetID: "subnet_id",
Region: "region",
Expand All @@ -45,9 +48,12 @@ func TestConfigValidate(t *testing.T) {
name: "missing subnet_id",
c: &Config{
Credentials: Credentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
CredentialType: AWSCredentialTypeStatic,
StaticCredentials: StaticCredentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
},
},
Region: "region",
},
Expand All @@ -57,21 +63,35 @@ func TestConfigValidate(t *testing.T) {
name: "missing region",
c: &Config{
Credentials: Credentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
CredentialType: AWSCredentialTypeStatic,
StaticCredentials: StaticCredentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
},
},
SubnetID: "subnet_id",
},
errString: "missing region",
},
{
name: "missing credentials",
name: "missing credential type",
c: &Config{
SubnetID: "subnet_id",
Region: "region",
},
errString: "failed to validate credentials: missing credential_type",
},
{
name: "invalid credential type",
c: &Config{
SubnetID: "subnet_id",
Region: "region",
Credentials: Credentials{
CredentialType: AWSCredentialType("bogus"),
},
},
errString: "failed to validate credentials: missing access_key_id",
errString: "failed to validate credentials: unknown credential type: bogus",
},
}

Expand All @@ -96,36 +116,48 @@ func TestCredentialsValidate(t *testing.T) {
{
name: "valid credentials",
c: Credentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
CredentialType: AWSCredentialTypeStatic,
StaticCredentials: StaticCredentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
},
},
errString: "",
},
{
name: "missing access_key_id",
c: Credentials{
AccessKeyID: "",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
CredentialType: AWSCredentialTypeStatic,
StaticCredentials: StaticCredentials{
AccessKeyID: "",
SecretAccessKey: "secret_access_key",
SessionToken: "session_token",
},
},
errString: "missing access_key_id",
},
{
name: "missing secret_access_key",
c: Credentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "",
SessionToken: "session_token",
CredentialType: AWSCredentialTypeStatic,
StaticCredentials: StaticCredentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "",
SessionToken: "session_token",
},
},
errString: "missing secret_access_key",
},
{
name: "missing session_token",
c: Credentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "",
CredentialType: AWSCredentialTypeStatic,
StaticCredentials: StaticCredentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret_access_key",
SessionToken: "",
},
},
errString: "missing session_token",
},
Expand Down Expand Up @@ -154,6 +186,8 @@ func TestNewConfig(t *testing.T) {
region = "region"
subnet_id = "subnet_id"
[credentials]
credential_type = "static"
[credentials.static]
access_key_id = "access_key_id"
secret_access_key = "secret"
session_token = "token"
Expand All @@ -171,9 +205,12 @@ func TestNewConfig(t *testing.T) {
require.NoError(t, err, "NewConfig() should not have returned an error")
require.Equal(t, &Config{
Credentials: Credentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret",
SessionToken: "token",
CredentialType: AWSCredentialTypeStatic,
StaticCredentials: StaticCredentials{
AccessKeyID: "access_key_id",
SecretAccessKey: "secret",
SessionToken: "token",
},
},
SubnetID: "subnet_id",
Region: "region",
Expand Down
28 changes: 14 additions & 14 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@ module github.com/cloudbase/garm-provider-aws
go 1.21.3

require (
github.com/BurntSushi/toml v1.3.2
github.com/aws/aws-sdk-go-v2 v1.27.0
github.com/aws/aws-sdk-go-v2/config v1.27.15
github.com/aws/aws-sdk-go-v2/credentials v1.17.15
github.com/aws/aws-sdk-go-v2/service/ec2 v1.161.3
github.com/BurntSushi/toml v1.4.0
github.com/aws/aws-sdk-go-v2 v1.29.0
github.com/aws/aws-sdk-go-v2/config v1.27.20
github.com/aws/aws-sdk-go-v2/credentials v1.17.20
github.com/aws/aws-sdk-go-v2/service/ec2 v1.165.0
github.com/aws/smithy-go v1.20.2
github.com/cloudbase/garm-provider-common v0.1.2
github.com/stretchr/testify v1.9.0
github.com/xeipuuv/gojsonschema v1.2.0
)

require (
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.7 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.8 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.13 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.21.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.29.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/google/uuid v1.6.0 // indirect
Expand All @@ -37,8 +37,8 @@ require (
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/sys v0.21.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading
Loading