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

Add Session tags and external id support for AWS Secrets #18813

Closed
wants to merge 7 commits into from

Conversation

harsimranmaan
Copy link
Contributor

@harsimranmaan harsimranmaan commented Jan 24, 2023

It is now possible to set the AWS session tags and external id when assuming an IAM role via STS AssumeRole.

Here's an example setup

AWS Role - Trust relationship needs the sts:TagSession permission set as described in https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_permissions-required

vault secrets enable aws
vault write aws/config/root access_key=<key> secret_key=<secret> region=us-west-2
vault write aws/roles/my-role credential_type=assumed_role max_sts_ttl=1h role_arns="arn:aws:iam::000000000000:role/test" session_tags="department=eng" session_tags="project=p1" external_id=123

Read the role definition

vault read  aws/roles/my-role
Key                         Value
---                         -----
credential_type             assumed_role
default_sts_ttl             0s
external_id                 123
iam_groups                  <nil>
iam_tags                    <nil>
max_sts_ttl                 1h
permissions_boundary_arn    n/a
policy_arns                 <nil>
policy_document             n/a
role_arns                   [arn:aws:iam::000000000000:role/test]
session_tags                map[department:eng project:p1]
user_path                   n/a
vault read  aws/sts/my-role
Key               Value
---               -----
access_key        XXXX
arn               arn:aws:sts::000000000000:assumed-role/test/vault-token-my-role-1674516375-mBKZQssrwtP6gl3kbmWq
secret_key        XXX
security_token    XXX
ttl               59m59s

The cloudtrail for AssumeRole looks like

	"userIdentity": {
        "type": "IAMUser",
        "principalId": "XXX",
        "arn": "arn:aws:iam::000000000000:user/vault-user",
        "accountId": "000000000000",
        "accessKeyId": "XXX",
        "userName": "vault-user"
    },
    "eventTime": "2023-01-23T23:31:12Z",
    "eventSource": "sts.amazonaws.com",
    "eventName": "AssumeRole",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "XXX",
    "userAgent": "aws-sdk-go/1.44.128 (go1.19.5; darwin; arm64)",
    "requestParameters": {
        "roleArn": "arn:aws:iam::000000000000:role/test",
        "roleSessionName": "vault-token-my-role-1674516375",
        "durationSeconds": 3600,
        "tags": [
            {
                "key": "department",
                "value": "eng"
            },
            {
                "key": "project",
                "value": "p1"
            }
        ],
        "externalId": "123"
    },
	...

When using the creds are used for accessing an S3 resource with Attribute-based Access Control (ABAC), you can now see that only requests with principalTag project=p1 are allowed while requests to path p2 are denied.

aws s3 cp a.txt s3://session-tags-test/p1/a.txt
upload: ./a.txt to s3://session-tags-test/p1/a.txt
➜  ~ aws s3 cp a.txt s3://session-tags-test/p2/a.txt
upload failed: ./a.txt to s3://session-tags-test/p2/a.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

The IAM policy had the following block in the above case

	{
            "Action": [
                "s3:Describe*",
                "s3:Get*",
                "s3:List*",
                "s3:PutObject*"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::session-tags-test/${aws:PrincipalTag/project}/*",
                "arn:aws:s3:::session-tags-test/${aws:PrincipalTag/project}"
            ]
        }

Troubleshooting:
Error:

 Error assuming role: AccessDenied: User: arn:aws:iam::000000000000:user/vault-user is not authorized to perform: sts:TagSession on resource: arn:aws:iam::000000000000:role/test
	status code: 403, request id: ba8ab60e-2fdf-4668-81ad-5fe83e9b898e

Remedy: Assign the sts:TagSession permission to the arn:aws:iam::000000000000:role/test. See https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_permissions-required

Error:

* Error assuming role: AccessDenied: User: arn:aws:iam::000000000000:user/vault-user is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::000000000000:role/test
	status code: 403, request id: c0117588-9c84-490d-9b36-91135545dec1

Remedy: If the external ID is set, follow https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html to ensure that external ID matches the ID set on the role. If you have not added the externalID condition on the role, it would not affect the assume role operation when an external ID is set only in Vault.

This change does not add support for transitive keys but it should be simple to add it in the future.

Closes #3790 #7960

@harsimranmaan
Copy link
Contributor Author

Hi @hsimon-hashicorp, any chance this could be reviewed by the team? Would like this to make the cut for 1.13

@snakebyte91
Copy link

Would be very good if you could pass the external id to the aws/sts endpoint:

vault write aws/sts/my-role ttl=10m external-id=<external-id>

So even a Vault admin could not assume the IAM role without the external id.

@harsimranmaan
Copy link
Contributor Author

harsimranmaan commented Aug 3, 2023

Would be very good if you could pass the external id to the aws/sts endpoint:

vault write aws/sts/my-role ttl=10m external-id=<external-id>

So even a Vault admin could not assume the IAM role without the external id.

That could be done as an extension to this but if you are a Vault admin, you can always decide to non-hmac the request keys and see what ext-id is being used.

It is now possible to set the AWS session tags and external id when assuming an IAM role
via STS AssumeRole.

Here's an example setup

AWS Role - Trust relationship needs the `sts:TagSession` permission set as described in https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_permissions-required
```bash
vault secrets enable aws
vault write aws/config/root access_key=<key> secret_key=<secret> region=us-west-2
vault write aws/roles/my-role credential_type=assumed_role max_sts_ttl=1h role_arns="arn:aws:iam::000000000000:role/test" session_tags="department=eng" session_tags="project=p1" external_id=123
```

Read the role definition
```
vault read  aws/roles/my-role
Key                         Value
---                         -----
credential_type             assumed_role
default_sts_ttl             0s
external_id                 123
iam_groups                  <nil>
iam_tags                    <nil>
max_sts_ttl                 1h
permissions_boundary_arn    n/a
policy_arns                 <nil>
policy_document             n/a
role_arns                   [arn:aws:iam::000000000000:role/test]
session_tags                map[department:eng project:p1]
user_path                   n/a
```

```bash
vault read  aws/sts/my-role
Key               Value
---               -----
access_key        XXXX
arn               arn:aws:sts::000000000000:assumed-role/test/vault-token-my-role-1674516375-mBKZQssrwtP6gl3kbmWq
secret_key        XXX
security_token    XXX
ttl               59m59s
```

The cloudtrail for AssumeRole looks like
```
	"userIdentity": {
        "type": "IAMUser",
        "principalId": "XXX",
        "arn": "arn:aws:iam::000000000000:user/vault-user",
        "accountId": "000000000000",
        "accessKeyId": "XXX",
        "userName": "vault-user"
    },
    "eventTime": "2023-01-23T23:31:12Z",
    "eventSource": "sts.amazonaws.com",
    "eventName": "AssumeRole",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "XXX",
    "userAgent": "aws-sdk-go/1.44.128 (go1.19.5; darwin; arm64)",
    "requestParameters": {
        "roleArn": "arn:aws:iam::000000000000:role/test",
        "roleSessionName": "vault-token-my-role-1674516375",
        "durationSeconds": 3600,
        "tags": [
            {
                "key": "department",
                "value": "eng"
            },
            {
                "key": "project",
                "value": "p1"
            }
        ],
        "externalId": "123"
    },
	...
```

When using the creds are used for accessing an S3 resource with Attribute-based Access Control (ABAC), you can now see that only requests with principalTag project=p1 are allowed while requests to path p2 are denied.

```
aws s3 cp a.txt s3://session-tags-test/p1/a.txt
upload: ./a.txt to s3://session-tags-test/p1/a.txt
➜  ~ aws s3 cp a.txt s3://session-tags-test/p2/a.txt
upload failed: ./a.txt to s3://session-tags-test/p2/a.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
```

The IAM policy had the following block in the above case
```
	{
            "Action": [
                "s3:Describe*",
                "s3:Get*",
                "s3:List*",
                "s3:PutObject*"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::session-tags-test/${aws:PrincipalTag/project}/*",
                "arn:aws:s3:::session-tags-test/${aws:PrincipalTag/project}"
            ]
        }
```

Troubleshooting:
Error:
```
 Error assuming role: AccessDenied: User: arn:aws:iam::000000000000:user/vault-user is not authorized to perform: sts:TagSession on resource: arn:aws:iam::000000000000:role/test
	status code: 403, request id: ba8ab60e-2fdf-4668-81ad-5fe83e9b898e
```

Remedy: Assign the `sts:TagSession` permission to the `arn:aws:iam::000000000000:role/test`. See https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_permissions-required

Error:
```
* Error assuming role: AccessDenied: User: arn:aws:iam::000000000000:user/vault-user is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::000000000000:role/test
	status code: 403, request id: c0117588-9c84-490d-9b36-91135545dec1
```
Remedy: If the external ID is set, follow https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html to ensure that external ID matches the ID set on the role. If you have not added the externalID condition on the role, it would not affect the assume role operation when an external ID is set only in Vault.

This change does not add support for transitive keys but it should be simple to add it in the future.

Closes hashicorp#3790 hashicorp#7960
@harsimranmaan
Copy link
Contributor Author

rebased and resolved merge conflicts.

@catrielg
Copy link

catrielg commented Mar 6, 2024

This feature is super useful and needed. Is there any ETA on when it will be available and documented?

@catrielg
Copy link

catrielg commented May 5, 2024

bump @hsimon-hashicorp + @harsimranmaan - any chance this can be implemented soon?

@edenzv
Copy link

edenzv commented Jun 19, 2024

I'm join to @catrielg that this feature is needed. @hsimon-hashicorp any chance this can be implemented soon?

@asvinours
Copy link

asvinours commented Jun 19, 2024

This was released in 1.17.0, I think it covers part of this request?

@leirtac12
Copy link

@asvinours You're correct, this does indeed cover part of this request. Unfortunately the feature that is most useful to me is the session tags part as we rely on them for ABAC.

@robmonte
Copy link
Member

Hi @harsimranmaan
Thank you for the contribution!

Would you be interested in updating this PR once again to account for recent changes causing merge conflicts? My initial look seems good but I'd like to give it a more thorough test after the conflicts get resolved.

Prefer to let the AWS API enforce its own constraints. If the max number
of tags is exceeded AWS will return an error.

In addition, the check was never being enforced since it as conditional
on an invalid config error.
@benashz benashz requested a review from a team as a code owner June 26, 2024 13:58
@benashz benashz modified the milestone: 1.17.1 Jun 26, 2024
Copy link
Member

@robmonte robmonte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! Seems like builtin/logical/aws/backend_test.go needs to be updated but only to account for the two new fields in the expected output then it's good to go!

@benashz benashz requested a review from a team as a code owner June 26, 2024 17:19
@benashz benashz self-requested a review June 26, 2024 17:20
@benashz
Copy link
Contributor

benashz commented Jun 26, 2024

Hi @harsimranmaan,

Since adding this feature requires more extensive testing, we are going to be taking over the work needed to land it. Thanks again for your contribution to HashiCorp!

-ben

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AWS backend stsAssume with "External ID"
9 participants