-
Notifications
You must be signed in to change notification settings - Fork 2.1k
AWS OIDC - DeployService: configure IAM #28088
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| /* | ||
| Copyright 2023 Gravitational, Inc. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| */ | ||
|
|
||
| package aws | ||
|
|
||
| import ( | ||
| "net/http" | ||
| "testing" | ||
|
|
||
| awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" | ||
| iamTypes "github.com/aws/aws-sdk-go-v2/service/iam/types" | ||
| "github.com/aws/aws-sdk-go/aws" | ||
| smithyhttp "github.com/aws/smithy-go/transport/http" | ||
| "github.com/gravitational/trace" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestConvertIAMv2Error(t *testing.T) { | ||
| for _, tt := range []struct { | ||
| name string | ||
| inErr error | ||
| errCheck require.ErrorAssertionFunc | ||
| }{ | ||
| { | ||
| name: "no error", | ||
| inErr: nil, | ||
| errCheck: require.NoError, | ||
| }, | ||
| { | ||
| name: "resource already exists", | ||
| inErr: &iamTypes.EntityAlreadyExistsException{ | ||
| Message: aws.String("resource exists"), | ||
| }, | ||
| errCheck: func(tt require.TestingT, err error, i ...interface{}) { | ||
| require.True(tt, trace.IsAlreadyExists(err), "expected trace.AlreadyExists error, got %v", err) | ||
| }, | ||
| }, | ||
| { | ||
| name: "resource already exists", | ||
| inErr: &iamTypes.NoSuchEntityException{ | ||
| Message: aws.String("resource not found"), | ||
| }, | ||
| errCheck: func(tt require.TestingT, err error, i ...interface{}) { | ||
| require.True(tt, trace.IsNotFound(err), "expected trace.NotFound error, got %v", err) | ||
| }, | ||
| }, | ||
| { | ||
| name: "invalid policy document", | ||
| inErr: &iamTypes.MalformedPolicyDocumentException{ | ||
| Message: aws.String("malformed document"), | ||
| }, | ||
| errCheck: func(tt require.TestingT, err error, i ...interface{}) { | ||
| require.True(tt, trace.IsBadParameter(err), "expected trace.BadParameter error, got %v", err) | ||
| }, | ||
| }, | ||
| { | ||
| name: "unauthorized", | ||
| inErr: &awshttp.ResponseError{ | ||
| ResponseError: &smithyhttp.ResponseError{ | ||
| Response: &smithyhttp.Response{Response: &http.Response{ | ||
| StatusCode: http.StatusForbidden, | ||
| }}, | ||
| Err: trace.Errorf(""), | ||
| }, | ||
| }, | ||
| errCheck: func(tt require.TestingT, err error, i ...interface{}) { | ||
| require.True(tt, trace.IsAccessDenied(err), "expected trace.AccessDenied error, got %v", err) | ||
| }, | ||
| }, | ||
| { | ||
| name: "not found", | ||
| inErr: &awshttp.ResponseError{ | ||
| ResponseError: &smithyhttp.ResponseError{ | ||
| Response: &smithyhttp.Response{Response: &http.Response{ | ||
| StatusCode: http.StatusNotFound, | ||
| }}, | ||
| Err: trace.Errorf(""), | ||
| }, | ||
| }, | ||
| errCheck: func(tt require.TestingT, err error, i ...interface{}) { | ||
| require.True(tt, trace.IsNotFound(err), "expected trace.NotFound error, got %v", err) | ||
| }, | ||
| }, | ||
| { | ||
| name: "resource already exists", | ||
| inErr: &awshttp.ResponseError{ | ||
| ResponseError: &smithyhttp.ResponseError{ | ||
| Response: &smithyhttp.Response{Response: &http.Response{ | ||
| StatusCode: http.StatusConflict, | ||
| }}, | ||
| Err: trace.Errorf(""), | ||
| }, | ||
| }, | ||
| errCheck: func(tt require.TestingT, err error, i ...interface{}) { | ||
| require.True(tt, trace.IsAlreadyExists(err), "expected trace.AlreadyExists error, got %v", err) | ||
| }, | ||
| }, | ||
| } { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| tt.errCheck(t, ConvertIAMv2Error(tt.inErr)) | ||
| }) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| /* | ||
| Copyright 2021 Gravitational, Inc. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| */ | ||
|
|
||
| package aws | ||
|
|
||
| var ( | ||
| allResources = []string{"*"} | ||
| ) | ||
|
|
||
| // StatementForIAMEditRolePolicy returns a IAM Policy Statement which allows editting Role Policy | ||
| // of the resources. | ||
| func StatementForIAMEditRolePolicy(resources ...string) *Statement { | ||
| return &Statement{ | ||
| Effect: EffectAllow, | ||
| Actions: []string{"iam:GetRolePolicy", "iam:PutRolePolicy", "iam:DeleteRolePolicy"}, | ||
| Resources: resources, | ||
| } | ||
| } | ||
|
|
||
| // StatementForIAMEditUserPolicy returns a IAM Policy Statement which allows editting User Policy | ||
| // of the resources. | ||
| func StatementForIAMEditUserPolicy(resources ...string) *Statement { | ||
| return &Statement{ | ||
| Effect: EffectAllow, | ||
| Actions: []string{"iam:GetUserPolicy", "iam:PutUserPolicy", "iam:DeleteUserPolicy"}, | ||
| Resources: resources, | ||
| } | ||
| } | ||
|
|
||
| // StatementForECSManageService returns the statement that allows managing the ECS Service deployed | ||
| // by DeployService (AWS OIDC Integration). | ||
| func StatementForECSManageService() *Statement { | ||
| return &Statement{ | ||
| Effect: EffectAllow, | ||
| Actions: []string{ | ||
| "ecs:DescribeClusters", "ecs:CreateCluster", "ecs:PutClusterCapacityProviders", | ||
| "ecs:DescribeServices", "ecs:CreateService", "ecs:UpdateService", | ||
| "ecs:RegisterTaskDefinition", | ||
| }, | ||
| Resources: allResources, | ||
| } | ||
| } | ||
|
|
||
| // StatementForWritingLogs returns the statement that allows the writing logs to CloudWatch. | ||
| // This is used by the DeployService (ECS Service) to write teleport logs. | ||
| // https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html | ||
| func StatementForWritingLogs() *Statement { | ||
| return &Statement{ | ||
| Effect: EffectAllow, | ||
| Actions: []string{"logs:CreateLogStream", "logs:PutLogEvents", "logs:CreateLogGroup"}, | ||
| Resources: allResources, | ||
| } | ||
| } | ||
|
|
||
| // StatementForIAMPassRole returns a statement that allows to iam:PassRole the target role. | ||
| // Usage example: when setting up the TaskRole for the ECS Task. | ||
| // https://docs.aws.amazon.com/AmazonECS/latest/userguide/task-iam-roles.html#specify-task-iam-roles | ||
| func StatementForIAMPassRole(targetRole string) *Statement { | ||
| return &Statement{ | ||
| Effect: EffectAllow, | ||
| Actions: SliceOrString{"iam:PassRole"}, | ||
| Resources: SliceOrString{ | ||
| targetRole, | ||
| }, | ||
| } | ||
| } | ||
|
|
||
| // StatementForECSTaskRoleTrustRelationships returns the Trust Relationship to allow the ECS Tasks service to. | ||
| // It allows the usage of this Role by the ECS Tasks service. | ||
| func StatementForECSTaskRoleTrustRelationships() *Statement { | ||
| return &Statement{ | ||
| Effect: EffectAllow, | ||
| Actions: SliceOrString{"sts:AssumeRole"}, | ||
| Principals: map[string]SliceOrString{ | ||
| "Service": {"ecs-tasks.amazonaws.com"}, | ||
| }, | ||
| } | ||
| } | ||
|
|
||
| // StatementForRDSDBConnect returns a statement that allows the `rds-db:connect` for all RDS DBs. | ||
| func StatementForRDSDBConnect() *Statement { | ||
| return &Statement{ | ||
| Effect: EffectAllow, | ||
| Actions: SliceOrString{"rds-db:connect"}, | ||
| Resources: allResources, | ||
| } | ||
| } | ||
|
Comment on lines
+93
to
+100
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there plan to support other DB types of deploy service? if so, ideally can share this with the db actions listed in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We will probably have more in the future 👍 There's indeed some duplication that we should get rid off. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to be consistent with the fields above
They use plural form but then the json tag is singular
Should we change them to singular as well?
ResourceandActionvsResourcesandActionsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I haven't notice this. Lets ignore my comment and keep this constant.