Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41a003eb9c |
No files matched your search
@@ -25,8 +25,6 @@ Credential rotation can be turned off by setting the
|
||||
This plugin will attempt to assume a role when a `role_arn` is supplied through the
|
||||
`attributes` object. More information about assume an AWS role can be found [here](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html). This feature only works when the plugin is running on a self managed Boundary [worker](https://developer.hashicorp.com/boundary/tutorials/hcp-administration/hcp-manage-workers).
|
||||
|
||||
To discover hosts across multiple AWS accounts, supply a `target_role_arn` in addition to `role_arn`. The plugin uses the principal credentials to assume the target role via a two-hop `AssumeRole` chain, enabling cross-account host discovery from a single worker. See [Attributes and Secrets](plugin/service/host/README.md#attributes-and-secrets) for the full list of `target_*` attributes.
|
||||
|
||||
### Environment Credentials
|
||||
|
||||
This plugin will attempt to retrieve credentials from environment variables. More
|
||||
|
||||
@@ -109,23 +109,13 @@ The following `attributes` are valid on an AWS host catalog resource:
|
||||
- `region` (string): The region to configure the host catalog for. All host sets
|
||||
in this catalog will be configured for this region.
|
||||
- `role_arn` (string): The AWS Role ARN used for `AssumeRole` authentication. If
|
||||
provided, `disable_credential_rotation` must be also set to `true`.
|
||||
- `role_external_id` (string): The external ID configured for the principal `AssumeRole`
|
||||
provided, `disable_credential_rotation` must be also set to `true.
|
||||
- `role_external_id` (string): The external id configured for the `AssumeRole`
|
||||
provider.
|
||||
- `role_session_name` (string): The session name configured for the principal `AssumeRole`
|
||||
- `role_session_name` (string): The session name configured for the `AssumeRole`
|
||||
provider.
|
||||
- `role_tags` (object): The key-value pair tags configured for the principal `AssumeRole`
|
||||
- `role_tags` (object): The key-value pair tags configured for the `AssumeRole`
|
||||
provider.
|
||||
- `target_role_arn` (string): The AWS role ARN of the target IAM role to assume for
|
||||
cross-account discovery. Required if any other `target_*` attributes are configured.
|
||||
- `target_region` (string): The region where the target hosts reside. Defaults to the
|
||||
principal account `region` if omitted.
|
||||
- `target_role_external_id` (string): The external ID configured for the target
|
||||
`AssumeRole` provider.
|
||||
- `target_role_session_name` (string): The session name configured for the target
|
||||
`AssumeRole` provider.
|
||||
- `target_role_tags` (object): The key-value pair tags configured for the target
|
||||
`AssumeRole` provider.
|
||||
|
||||
The following `secrets` are required on an AWS host catalog resource:
|
||||
|
||||
|
||||
@@ -83,12 +83,8 @@ func (p *HostPlugin) OnCreateCatalog(ctx context.Context, req *pb.OnCreateCatalo
|
||||
}
|
||||
|
||||
// perform dry run to ensure we can interact with AWS as expected.
|
||||
opts := []ec2Option{}
|
||||
if catalogAttributes.DualStack {
|
||||
opts = append(opts, WithDualStack(catalogAttributes.DualStack))
|
||||
}
|
||||
if st := dryRunValidation(ctx, catalogState, opts); st != nil {
|
||||
return nil, st.Err()
|
||||
if err := performDryRun(ctx, catalogAttributes, catalogState, &SetAttributes{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
persistedProto, err := catalogState.toProto()
|
||||
@@ -171,12 +167,10 @@ func (p *HostPlugin) OnUpdateCatalog(ctx context.Context, req *pb.OnUpdateCatalo
|
||||
if err != nil {
|
||||
return nil, errors.BadRequestStatusf("error loading persisted state: %s", err)
|
||||
}
|
||||
opts := []ec2Option{}
|
||||
if newCatalogAttributes.DualStack {
|
||||
opts = append(opts, WithDualStack(newCatalogAttributes.DualStack))
|
||||
}
|
||||
if st := dryRunValidation(ctx, newCatalogState, opts); st != nil {
|
||||
return nil, st.Err()
|
||||
|
||||
// perform dry run to ensure we can interact with AWS as expected.
|
||||
if err := performDryRun(ctx, newCatalogAttributes, newCatalogState, &SetAttributes{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Replace the existing credential state.
|
||||
@@ -217,12 +211,8 @@ func (p *HostPlugin) OnUpdateCatalog(ctx context.Context, req *pb.OnUpdateCatalo
|
||||
}
|
||||
|
||||
// perform dry run to ensure we can interact with AWS as expected.
|
||||
opts := []ec2Option{}
|
||||
if newCatalogAttributes.DualStack {
|
||||
opts = append(opts, WithDualStack(newCatalogAttributes.DualStack))
|
||||
}
|
||||
if st := dryRunValidation(ctx, catalogState, opts); st != nil {
|
||||
return nil, st.Err()
|
||||
if err := performDryRun(ctx, newCatalogAttributes, catalogState, &SetAttributes{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
persistedProto, err := catalogState.toProto()
|
||||
@@ -366,18 +356,11 @@ func (p *HostPlugin) OnCreateSet(ctx context.Context, req *pb.OnCreateSetRequest
|
||||
return nil, err
|
||||
}
|
||||
|
||||
describeInstanceFilters, err := buildFilters(setAttrs)
|
||||
if err != nil {
|
||||
return nil, errors.BadRequestStatusf("error building set filters: %s", err)
|
||||
// perform dry run to ensure we can interact with AWS as expected.
|
||||
if err := performDryRun(ctx, catalogAttributes, catalogState, setAttrs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts := []ec2Option{}
|
||||
if catalogAttributes.DualStack {
|
||||
opts = append(opts, WithDualStack(catalogAttributes.DualStack))
|
||||
}
|
||||
if st := dryRunValidation(ctx, catalogState, opts, describeInstanceFilters...); st != nil {
|
||||
return nil, st.Err()
|
||||
}
|
||||
return &pb.OnCreateSetResponse{}, nil
|
||||
}
|
||||
|
||||
@@ -431,17 +414,9 @@ func (p *HostPlugin) OnUpdateSet(ctx context.Context, req *pb.OnUpdateSetRequest
|
||||
return nil, err
|
||||
}
|
||||
|
||||
describeInstanceFilters, err := buildFilters(setAttrs)
|
||||
if err != nil {
|
||||
return nil, errors.BadRequestStatusf("error building set filters: %s", err)
|
||||
}
|
||||
|
||||
opts := []ec2Option{}
|
||||
if catalogAttributes.DualStack {
|
||||
opts = append(opts, WithDualStack(catalogAttributes.DualStack))
|
||||
}
|
||||
if st := dryRunValidation(ctx, catalogState, opts, describeInstanceFilters...); st != nil {
|
||||
return nil, st.Err()
|
||||
// perform dry run to ensure we can interact with AWS as expected.
|
||||
if err := performDryRun(ctx, catalogAttributes, catalogState, setAttrs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.OnUpdateSetResponse{}, nil
|
||||
@@ -729,6 +704,40 @@ func dryRunValidation(ctx context.Context, state *awsCatalogPersistedState, ec2O
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkHosts performs a dry-run AWS DescribeInstances call using the provided
|
||||
// input to verify the states credentials and any filters. This replaces
|
||||
// dryRunValidation for handlers that have already built a DescribeInstancesInput.
|
||||
func checkHosts(ctx context.Context, state *awsCatalogPersistedState, ec2Opts []ec2Option, input *ec2.DescribeInstancesInput) error {
|
||||
if state == nil {
|
||||
return errors.BadRequestStatus("persisted state is required")
|
||||
}
|
||||
|
||||
ec2Client, err := state.EC2Client(ctx, ec2Opts...)
|
||||
|
||||
if err != nil {
|
||||
return errors.BadRequestStatusf("error getting EC2 client: %s", err)
|
||||
}
|
||||
|
||||
if _, err := ec2Client.DescribeInstances(ctx, input); err != nil {
|
||||
return status.Errorf(codes.FailedPrecondition, "aws describe instances failed: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// performDryRun builds a dry-run DescribeInstances input from the provided
|
||||
// set attributes and calls checkHosts to verify the catalog state's credentials.
|
||||
func performDryRun(ctx context.Context, catalogAttributes *CatalogAttributes, catalogState *awsCatalogPersistedState, setAttrs *SetAttributes) error {
|
||||
opts := []ec2Option{}
|
||||
if catalogAttributes.DualStack {
|
||||
opts = append(opts, WithDualStack(catalogAttributes.DualStack))
|
||||
}
|
||||
input, err := buildDescribeInstancesInput(setAttrs, true)
|
||||
if err != nil {
|
||||
return errors.BadRequestStatusf("error building DescribeInstances input: %s", err)
|
||||
}
|
||||
return checkHosts(ctx, catalogState, opts, input)
|
||||
}
|
||||
|
||||
// appendDistinct will append the elements to the slice
|
||||
// if an element is not nil, empty, and does not exist in slice.
|
||||
func appendDistinct(slice []string, elems ...*string) []string {
|
||||
|
||||
Reference in new issue
Block a user