Skip to content

Commit

Permalink
aws auth - add support for iam_metadata and ec2_metadata params (#…
Browse files Browse the repository at this point in the history
…1125)

* Add support for iam_metadata and ec2_metadata params, and integration tests for configure_identity_integration

* change string semicolon to dash to satisfy flake8

* Apply suggestions from code review

---------

Co-authored-by: Brian Scholer <1260690+briantist@users.noreply.github.com>
  • Loading branch information
danholodak and briantist committed Jan 27, 2024
1 parent f7688e2 commit 8cb35eb
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 13 deletions.
41 changes: 28 additions & 13 deletions hvac/api/auth_methods/aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,12 @@ def delete_config(self, mount_point=AWS_DEFAULT_MOUNT_POINT):
return self._adapter.delete(url=api_path)

def configure_identity_integration(
self, iam_alias=None, ec2_alias=None, mount_point=AWS_DEFAULT_MOUNT_POINT
self,
iam_alias=None,
ec2_alias=None,
mount_point=AWS_DEFAULT_MOUNT_POINT,
iam_metadata=None,
ec2_metadata=None,
):
"""Configure the way that Vault interacts with the Identity store.
Expand All @@ -146,34 +151,44 @@ def configure_identity_integration(
select full_arn and then delete and recreate the IAM role, Vault won't be aware and any identity aliases
set up for the role name will still be valid
:type iam_alias: str | unicode
:param iam_metadata: The metadata to include on the token returned by the login endpoint.
This metadata will be added to both audit logs, and on the ``iam_alias``. By default, it includes ``account_id``
and ``auth_type``. Additionally, ``canonical_arn``, ``client_arn``, ``client_user_id``, ``inferred_aws_region``, ``inferred_entity_id``,
and ``inferred_entity_type`` are available. To include no metadata, set to an empty list ``[]``.
To use only particular fields, select the explicit fields. To restore to defaults, send only a field of ``default``.
Only select fields that will have a low rate of change for your ``iam_alias`` because each change triggers a storage
write and can have a performance impact at scale.
:type iam_metadata: str | unicode | list
:param ec2_alias: Configures how to generate the identity alias when using the ec2 auth method. Valid choices
are role_id, instance_id, and image_id. When role_id is selected, the randomly generated ID of the role is
used. When instance_id is selected, the instance identifier is used as the identity alias name. When
image_id is selected, AMI ID of the instance is used as the identity alias name
:type ec2_alias: str | unicode
:param ec2_metadata: The metadata to include on the token returned by the login endpoint. This metadata will be
added to both audit logs, and on the ``ec2_alias``. By default, it includes ``account_id`` and ``auth_type``. Additionally,
``ami_id``, ``instance_id``, and ``region`` are available. To include no metadata, set to an empty list ``[]``.
To use only particular fields, select the explicit fields. To restore to defaults, send only a field of ``default``.
Only select fields that will have a low rate of change for your ``ec2_alias`` because each change triggers a storage
write and can have a performance impact at scale.
:type ec2_metadata: str | unicode | list
:param mount_point: The path the AWS auth method was mounted on.
:type mount_point: str | unicode
:return: The response of the request
:rtype: request.Response
"""
if iam_alias is not None and iam_alias not in ALLOWED_IAM_ALIAS_TYPES:
error_msg = 'invalid iam alias type provided: "{arg}"; supported iam alias types: "{alias_types}"'
raise exceptions.ParamValidationError(
error_msg.format(
arg=iam_alias, environments=",".join(ALLOWED_IAM_ALIAS_TYPES)
)
)
error_msg = f"invalid iam alias type provided: '{iam_alias}' - supported iam alias types: '{','.join(ALLOWED_IAM_ALIAS_TYPES)}'"
raise exceptions.ParamValidationError(error_msg)
if ec2_alias is not None and ec2_alias not in ALLOWED_EC2_ALIAS_TYPES:
error_msg = 'invalid ec2 alias type provided: "{arg}"; supported ec2 alias types: "{alias_types}"'
raise exceptions.ParamValidationError(
error_msg.format(
arg=ec2_alias, environments=",".join(ALLOWED_EC2_ALIAS_TYPES)
)
)
error_msg = f"invalid ec2 alias type provided: '{ec2_alias}' - supported ec2 alias types: '{','.join(ALLOWED_EC2_ALIAS_TYPES)}'"
raise exceptions.ParamValidationError(error_msg)

params = utils.remove_nones(
{
"iam_alias": iam_alias,
"ec2_alias": ec2_alias,
"ec2_metadata": ec2_metadata,
"iam_metadata": iam_metadata,
}
)
api_auth = "/v1/auth/{mount_point}/config/identity".format(
Expand Down
127 changes: 127 additions & 0 deletions tests/integration_tests/api/auth_methods/test_aws.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
from unittest import TestCase

from parameterized import parameterized, param

from hvac import exceptions
from tests.utils.hvac_integration_test_case import HvacIntegrationTestCase


class TestAws(HvacIntegrationTestCase, TestCase):
TEST_MOUNT_POINT = "aws-test"

def setUp(self):
super().setUp()
if "%s/" % self.TEST_MOUNT_POINT not in self.client.sys.list_auth_methods():
self.client.sys.enable_auth_method(
method_type="aws",
path=self.TEST_MOUNT_POINT,
)

def tearDown(self):
super().tearDown()
self.client.sys.disable_auth_method(
path=self.TEST_MOUNT_POINT,
)

@parameterized.expand(
[
param(
"no params",
),
param(
"valid iam metadata input 1",
iam_metadata="default",
),
param(
"valid iam metadata input 2",
iam_metadata=["auth_type", "client_arn", "inferred_aws_region"],
),
param(
"valid ec2 metadata input 1",
ec2_metadata=["region", "ami_id", "account_id"],
),
param("valid ec2 metadata input 2", ec2_metadata="default"),
param("valid ec2 alias input 1", ec2_alias="instance_id"),
param("valid ec2 alias input 2", ec2_alias="role_id"),
param("valid iam alias input 1", iam_alias="full_arn"),
param("valid iam alias input 2", iam_alias="role_id"),
param(
"valid combination",
ec2_metadata=["region", "instance_id", "auth_type"],
iam_metadata=[
"inferred_entity_type",
"inferred_entity_id",
"canonical_arn",
"client_user_id",
"account_id",
],
ec2_alias="image_id",
iam_alias="unique_id",
),
]
)
def test_configure_identity_integration_succeeds(
self, label, ec2_metadata="", iam_metadata="", ec2_alias=None, iam_alias=None
):
configure_response = self.client.auth.aws.configure_identity_integration(
mount_point=self.TEST_MOUNT_POINT,
ec2_metadata=ec2_metadata,
iam_metadata=iam_metadata,
ec2_alias=ec2_alias,
iam_alias=iam_alias,
)
self.assertEqual(
first=bool(configure_response),
second=True,
)

@parameterized.expand(
[
param(
"invalid ec2 metadata",
raises=exceptions.InvalidRequest,
exception_message="contains an unavailable field, please select from",
ec2_metadata="something invalid",
),
param(
"invalid iam metadata",
iam_metadata="something invalid",
raises=exceptions.InvalidRequest,
exception_message="contains an unavailable field, please select from",
),
param(
"invalid iam alias",
iam_alias="something invalid",
raises=exceptions.ParamValidationError,
exception_message="invalid iam alias type provided",
),
param(
"invalid ec2 alias",
ec2_alias="something invalid",
raises=exceptions.ParamValidationError,
exception_message="invalid ec2 alias type provided",
),
]
)
def test_configure_identity_integration_fails(
self,
label,
raises,
exception_message,
ec2_metadata=None,
iam_metadata=None,
ec2_alias=None,
iam_alias=None,
):
with self.assertRaises(raises) as cm:
self.client.auth.aws.configure_identity_integration(
mount_point=self.TEST_MOUNT_POINT,
ec2_metadata=ec2_metadata,
iam_metadata=iam_metadata,
ec2_alias=ec2_alias,
iam_alias=iam_alias,
)
self.assertIn(
member=exception_message,
container=str(cm.exception),
)

0 comments on commit 8cb35eb

Please sign in to comment.