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

implement irsa server side support #7738

Merged
merged 47 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
82c4e21
wip
nithyatsu Jul 3, 2024
da00735
nit
nithyatsu Jul 3, 2024
b2a3346
add controller for irsa
nithyatsu Jun 28, 2024
0c6c70f
wip
nithyatsu Jul 1, 2024
b882cea
fix format
nithyatsu Jul 1, 2024
ae208bf
wip
nithyatsu Jul 4, 2024
c684ec5
nit
nithyatsu Jul 10, 2024
c94b3cd
nit ffixes
nithyatsu Jul 10, 2024
177c928
nit
nithyatsu Jul 10, 2024
cf36491
fix
nithyatsu Jul 10, 2024
2f736ba
fix format
nithyatsu Jul 10, 2024
487b2ac
Delete pkg/cli/bicep/gomock_reflect_553958658/prog.go
nithyatsu Jul 10, 2024
3822f0f
nit
nithyatsu Jul 10, 2024
2a08928
nit
nithyatsu Jul 10, 2024
964ee1f
correct descriptions
nithyatsu Jul 10, 2024
47109bb
fix description
nithyatsu Jul 10, 2024
04d73da
add UT for IRSA datamodel convertors
nithyatsu Jul 10, 2024
ea0c7b6
nit
nithyatsu Jul 10, 2024
e14898c
nit
nithyatsu Jul 12, 2024
3e7a546
working code - needs env
nithyatsu Jul 13, 2024
26f822f
wip
nithyatsu Jul 13, 2024
272f706
wip
nithyatsu Jul 15, 2024
ddade16
draft
nithyatsu Jul 17, 2024
92ab035
draft
nithyatsu Jul 17, 2024
6ba78e3
wip
nithyatsu Jul 19, 2024
edc75f8
draft
nithyatsu Jul 19, 2024
bfb6eda
revert yaml changes
nithyatsu Jul 19, 2024
2e77de3
wip
nithyatsu Jul 19, 2024
bdc5770
wip
nithyatsu Jul 19, 2024
9af7d77
nits
nithyatsu Jul 19, 2024
3f8af4e
wip
nithyatsu Jul 19, 2024
f67fd5f
wip
nithyatsu Jul 19, 2024
ce9ca57
nit
nithyatsu Jul 19, 2024
9451551
nit
nithyatsu Jul 19, 2024
e89f8ef
fix test
nithyatsu Jul 19, 2024
1596ca5
wip
nithyatsu Jul 19, 2024
455b536
nit
nithyatsu Jul 19, 2024
4781892
add review feedback
nithyatsu Jul 24, 2024
5a7d269
move strings to constants
nithyatsu Jul 25, 2024
684c4b7
add const string
nithyatsu Jul 25, 2024
b2ea275
refactor
nithyatsu Jul 26, 2024
e551090
add UT
nithyatsu Jul 26, 2024
6146e11
refactor
nithyatsu Jul 26, 2024
19a51b7
refactor
nithyatsu Jul 29, 2024
7cded5a
wip
nithyatsu Jul 29, 2024
e6fe44f
incorp review comments
nithyatsu Jul 29, 2024
007f7e6
Merge branch 'main' into ucp_irsa
kachawla Jul 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 34 additions & 5 deletions pkg/recipes/terraform/config/providers/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"errors"
"fmt"

"github.com/google/uuid"
ucp_datamodel "github.com/radius-project/radius/pkg/ucp/datamodel"

"github.com/radius-project/radius/pkg/azure/tokencredentials"
Expand All @@ -43,6 +44,17 @@ const (
awsRegionParam = "region"
awsAccessKeyParam = "access_key"
awsSecretKeyParam = "secret_key"

lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved
// configs for AWS IRSA
// Ref: https://registry.terraform.io/providers/hashicorp/aws/latest/docs#assuming-an-iam-role-using-a-web-identity
awsIRSAProvider = "assume_role_with_web_identity"
awsRoleARN = "role_arn"
sessionName = "session_name"
tokenFile = "web_identity_token_file"
// The path used in Amazon Elastic Kubernetes Service (EKS) to store the service account token for a Kubernetes pod.
// Ref: https://docs.aws.amazon.com/eks/latest/userguide/pod-configuration.html
tokenFilePath = "/var/run/secrets/eks.amazonaws.com/serviceaccount/token"
sessionPrefix = "radius-terraform-"
)

var _ Provider = (*awsProvider)(nil)
Expand Down Expand Up @@ -127,7 +139,10 @@ func fetchAWSCredentials(ctx context.Context, awsCredentialsProvider credentials
return nil, nil
}
case ucp_datamodel.AWSIRSACredentialKind:
return nil, errors.New("AWS IRSA Credential is not supported yet.")
if credentials.IRSACredential == nil || credentials.IRSACredential.RoleARN == "" {
logger.Info("AWS IRSA credentials are not registered, skipping credentials configuration.")
return nil, nil
}
}

return credentials, nil
Expand All @@ -139,10 +154,24 @@ func (p *awsProvider) generateProviderConfigMap(credentials *credentials.AWSCred
config[awsRegionParam] = region
}

if credentials != nil && credentials.AccessKeyCredential != nil &&
credentials.AccessKeyCredential.AccessKeyID != "" && credentials.AccessKeyCredential.SecretAccessKey != "" {
config[awsAccessKeyParam] = credentials.AccessKeyCredential.AccessKeyID
config[awsSecretKeyParam] = credentials.AccessKeyCredential.SecretAccessKey
if credentials != nil {
switch credentials.Kind {
case ucp_datamodel.AWSAccessKeyCredentialKind:
if credentials.AccessKeyCredential != nil &&
credentials.AccessKeyCredential.AccessKeyID != "" && credentials.AccessKeyCredential.SecretAccessKey != "" {
config[awsAccessKeyParam] = credentials.AccessKeyCredential.AccessKeyID
config[awsSecretKeyParam] = credentials.AccessKeyCredential.SecretAccessKey
}

case ucp_datamodel.AWSIRSACredentialKind:
if credentials.IRSACredential != nil && credentials.IRSACredential.RoleARN != "" {
config[awsIRSAProvider] = map[string]any{
awsRoleARN: credentials.IRSACredential.RoleARN,
sessionName: sessionPrefix + uuid.New().String(),
tokenFile: tokenFilePath,
}
}
}
}

return config
Expand Down
146 changes: 118 additions & 28 deletions pkg/recipes/terraform/config/providers/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,44 @@ import (
)

var (
testRegion = "test-region"
testAWSCredentials = ucp_credentials.AWSCredential{
testRegion = "test-region"
testAWSAccessKeyCredentials = ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSAccessKeyCredentialKind,
AccessKeyCredential: &ucp_datamodel.AWSAccessKeyCredentialProperties{
AccessKeyID: "testAccessKey",
SecretAccessKey: "testSecretKey",
},
}
testAWSIRSACredentials = ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSIRSACredentialKind,
IRSACredential: &ucp_datamodel.AWSIRSACredentialProperties{
RoleARN: "testRoleARN",
},
}
)

type mockAWSCredentialsProvider struct {
testCredential *ucp_credentials.AWSCredential
}

func newMockAWSCredentialsProvider() *mockAWSCredentialsProvider {
func newMockAWSAccessKeyCredentialsProvider() *mockAWSCredentialsProvider {
return &mockAWSCredentialsProvider{
testCredential: &ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSAccessKeyCredentialKind,
AccessKeyCredential: &ucp_datamodel.AWSAccessKeyCredentialProperties{
AccessKeyID: testAWSCredentials.AccessKeyCredential.AccessKeyID,
SecretAccessKey: testAWSCredentials.AccessKeyCredential.SecretAccessKey,
AccessKeyID: testAWSAccessKeyCredentials.AccessKeyCredential.AccessKeyID,
SecretAccessKey: testAWSAccessKeyCredentials.AccessKeyCredential.SecretAccessKey,
},
},
}
}

func newMockAWSIRSACredentialsProvider() *mockAWSCredentialsProvider {
return &mockAWSCredentialsProvider{
testCredential: &ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSIRSACredentialKind,
IRSACredential: &ucp_datamodel.AWSIRSACredentialProperties{
RoleARN: testAWSIRSACredentials.IRSACredential.RoleARN,
},
},
}
Expand All @@ -66,12 +83,20 @@ func (p *mockAWSCredentialsProvider) Fetch(ctx context.Context, planeName, name
return nil, &secret.ErrNotFound{}
}

if p.testCredential.AccessKeyCredential.AccessKeyID == "" && p.testCredential.AccessKeyCredential.SecretAccessKey == "" {
return p.testCredential, nil
}
switch p.testCredential.Kind {
case ucp_datamodel.AWSAccessKeyCredentialKind:
if p.testCredential.AccessKeyCredential.AccessKeyID == "" && p.testCredential.AccessKeyCredential.SecretAccessKey == "" {
return p.testCredential, nil
}

if p.testCredential.AccessKeyCredential.AccessKeyID == "" {
return nil, errors.New("failed to fetch credential")
if p.testCredential.AccessKeyCredential.AccessKeyID == "" {
return nil, errors.New("failed to fetch credential")
}

case ucp_datamodel.AWSIRSACredentialKind:
if p.testCredential.IRSACredential.RoleARN == "" {
return nil, errors.New("failed to fetch credential")
}
}

return p.testCredential, nil
Expand Down Expand Up @@ -185,17 +210,17 @@ func TestAwsProvider_getCredentialsProvider(t *testing.T) {
require.NoError(t, err)
}

func TestAWSProvider_FetchCredentials(t *testing.T) {
func TestAWSProvider_FetchAcessKeyCredentials(t *testing.T) {
tests := []struct {
desc string
credentialsProvider *mockAWSCredentialsProvider
expectedCreds *ucp_credentials.AWSCredential
expectedErr bool
}{
{
desc: "valid credentials",
credentialsProvider: newMockAWSCredentialsProvider(),
expectedCreds: &testAWSCredentials,
desc: "valid accesskey credentials",
credentialsProvider: newMockAWSAccessKeyCredentialsProvider(),
expectedCreds: &testAWSAccessKeyCredentials,
expectedErr: false,
},
{
Expand All @@ -207,27 +232,60 @@ func TestAWSProvider_FetchCredentials(t *testing.T) {
expectedErr: false,
},
{
desc: "empty values - no error",
desc: "empty values aws access key - no error",
credentialsProvider: &mockAWSCredentialsProvider{
&ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSAccessKeyCredentialKind,
AccessKeyCredential: &ucp_datamodel.AWSAccessKeyCredentialProperties{
AccessKeyID: testAWSCredentials.AccessKeyCredential.AccessKeyID,
SecretAccessKey: testAWSCredentials.AccessKeyCredential.SecretAccessKey,
AccessKeyID: testAWSAccessKeyCredentials.AccessKeyCredential.AccessKeyID,
SecretAccessKey: testAWSAccessKeyCredentials.AccessKeyCredential.SecretAccessKey,
},
},
},
expectedCreds: nil,
expectedErr: false,
},
{
desc: "fetch credential error",
desc: "fetch accesskey credential error",
credentialsProvider: &mockAWSCredentialsProvider{
&ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSAccessKeyCredentialKind,
AccessKeyCredential: &ucp_datamodel.AWSAccessKeyCredentialProperties{
AccessKeyID: "",
SecretAccessKey: testAWSCredentials.AccessKeyCredential.SecretAccessKey,
SecretAccessKey: testAWSAccessKeyCredentials.AccessKeyCredential.SecretAccessKey,
},
},
},
expectedCreds: nil,
expectedErr: true,
},

{
desc: "valid IRSA credentials",
credentialsProvider: newMockAWSIRSACredentialsProvider(),
expectedCreds: &testAWSIRSACredentials,
expectedErr: false,
},
{
desc: "empty values aws IRSA - no error",
credentialsProvider: &mockAWSCredentialsProvider{
&ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSIRSACredentialKind,
IRSACredential: &ucp_datamodel.AWSIRSACredentialProperties{
RoleARN: testAWSIRSACredentials.IRSACredential.RoleARN,
},
},
},
expectedCreds: nil,
expectedErr: false,
},
{
desc: "fetch IRSA credential error",
credentialsProvider: &mockAWSCredentialsProvider{
&ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSIRSACredentialKind,
IRSACredential: &ucp_datamodel.AWSIRSACredentialProperties{
RoleARN: "",
},
},
},
Expand Down Expand Up @@ -260,21 +318,35 @@ func TestAWSProvider_generateProviderConfigMap(t *testing.T) {
expectedConfig map[string]any
}{
{
desc: "valid config",
desc: "valid accesskey credential config",
region: testRegion,
credentials: testAWSCredentials,
credentials: testAWSAccessKeyCredentials,
expectedConfig: map[string]any{
awsRegionParam: testRegion,
awsAccessKeyParam: testAWSCredentials.AccessKeyCredential.AccessKeyID,
awsSecretKeyParam: testAWSCredentials.AccessKeyCredential.SecretAccessKey,
awsAccessKeyParam: testAWSAccessKeyCredentials.AccessKeyCredential.AccessKeyID,
awsSecretKeyParam: testAWSAccessKeyCredentials.AccessKeyCredential.SecretAccessKey,
},
},

{
desc: "valid IRSA credential config",
region: testRegion,
credentials: testAWSIRSACredentials,
expectedConfig: map[string]any{
awsRegionParam: testRegion,
awsIRSAProvider: map[string]any{
awsRoleARN: testAWSIRSACredentials.IRSACredential.RoleARN,
sessionName: "radius-terraform-" + "test-uuid",
tokenFile: tokenFilePath,
},
},
},
{
desc: "missing region",
credentials: testAWSCredentials,
credentials: testAWSAccessKeyCredentials,
expectedConfig: map[string]any{
awsAccessKeyParam: testAWSCredentials.AccessKeyCredential.AccessKeyID,
awsSecretKeyParam: testAWSCredentials.AccessKeyCredential.SecretAccessKey,
awsAccessKeyParam: testAWSAccessKeyCredentials.AccessKeyCredential.AccessKeyID,
awsSecretKeyParam: testAWSAccessKeyCredentials.AccessKeyCredential.SecretAccessKey,
},
},
{
Expand All @@ -285,12 +357,22 @@ func TestAWSProvider_generateProviderConfigMap(t *testing.T) {
},
},
{
desc: "invalid credentials",
desc: "invalid accesskey credentials",
credentials: ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSAccessKeyCredentialKind,
AccessKeyCredential: &ucp_datamodel.AWSAccessKeyCredentialProperties{
AccessKeyID: "",
SecretAccessKey: testAWSCredentials.AccessKeyCredential.SecretAccessKey,
SecretAccessKey: testAWSAccessKeyCredentials.AccessKeyCredential.SecretAccessKey,
},
},
expectedConfig: map[string]any{},
},
{
desc: "invalid IRSA credentials",
credentials: ucp_credentials.AWSCredential{
Kind: ucp_datamodel.AWSIRSACredentialKind,
IRSACredential: &ucp_datamodel.AWSIRSACredentialProperties{
RoleARN: "",
},
},
expectedConfig: map[string]any{},
Expand All @@ -305,6 +387,14 @@ func TestAWSProvider_generateProviderConfigMap(t *testing.T) {
require.Equal(t, tt.expectedConfig[awsRegionParam], config[awsRegionParam])
require.Equal(t, tt.expectedConfig[awsAccessKeyParam], config[awsAccessKeyParam])
require.Equal(t, tt.expectedConfig[awsSecretKeyParam], config[awsSecretKeyParam])

if tt.expectedConfig[awsIRSAProvider] != nil {
expectedAWSIRSAProvider := tt.expectedConfig[awsIRSAProvider].(map[string]any)
AWSIRSAProvider := config[awsIRSAProvider].(map[string]any)
require.Equal(t, expectedAWSIRSAProvider[awsRoleARN], AWSIRSAProvider[awsRoleARN])
require.Contains(t, expectedAWSIRSAProvider[sessionName], "radius-terraform-")
require.Equal(t, expectedAWSIRSAProvider[tokenFile], AWSIRSAProvider[tokenFile])
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"awsCredential": {
"kind": "IRSA",
"irsa": {
"roleARN": "arn:aws:iam::000000000000:role/role-name"
"roleARN": "arn:aws:iam::000000000000:role/role-name"
}
},
"storage": {
Expand Down
Loading