Skip to content

Commit

Permalink
Address comments on PR
Browse files Browse the repository at this point in the history
* Only required rolesanywhere:UpdateTrustAnchor permissions (no creating
  or listing)
* Add note about how this plugin is only supported when an
  UpstreamAuthority plugin is also used
* Use ID instead of trust anchor name to identify trust anchors, as it's
  unique
* Check that certificate bundles don't exceed a length of 8000 before
  making the UpdateTrustAnchor API call
* Make corresponding changes to unit tests

Signed-off-by: Ajay Gupta <apg76@cornell.edu>
  • Loading branch information
ajay1135 committed Jun 16, 2024
1 parent ec57f30 commit 7713757
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 267 deletions.
4 changes: 2 additions & 2 deletions conf/server/server_full.conf
Original file line number Diff line number Diff line change
Expand Up @@ -938,8 +938,8 @@ plugins {
# # AWS_SECRET_ACCESS_KEY environment variable.
# # secret_access_key = ""

# # trust_anchor_name: The AWS IAM Roles Anywhere trust anchor name to which to store the trust bundle. Default: "".
# # trust_anchor_name = "spire-trust-anchor"
# # trust_anchor_id: The AWS IAM Roles Anywhere trust anchor id of the trust anchor to which to put the trust bundle. Default: "".
# # trust_anchor_id = "153d3e58-cab5-4a59-a0a1-3febad2937c4"
# }
# }
}
Expand Down
21 changes: 11 additions & 10 deletions doc/plugin_server_bundlepublisher_aws_rolesanywhere_trustanchor.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
# Server plugin: BundlePublisher "aws_rolesanywhere_trustanchor"

**Note: This plugin is only supported when an UpstreamAuthority plugin is used.**

The `aws_rolesanywhere_trustanchor` plugin puts the current trust bundle of the server
in a trust anchor, keeping it updated. If a trust anchor with the specified name doesn't
already exist, it will be created.
in a trust anchor, keeping it updated.

The plugin accepts the following configuration options:

| Configuration | Description | Required | Default |
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------|------------------------------------------------------|
| access_key_id | AWS access key id. | Required only if AWS credentials aren't otherwise set in the environment. | Value of AWS_ACCESS_KEY_ID environment variable. |
| secret_access_key | AWS secret access key. | Required only if AWS credentials aren't otherwise set in the environment. | Value of AWS_SECRET_ACCESS_KEY environment variable. |
| region | AWS region to store the trust bundle. | Yes. | |
| trust_anchor_name | The AWS IAM Roles Anywhere trust anchor name to which to put the trust bundle. | Yes. | |
| Configuration | Description | Required | Default |
|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------|------------------------------------------------------|
| access_key_id | AWS access key id. | Required only if AWS credentials aren't otherwise set in the environment. | Value of AWS_ACCESS_KEY_ID environment variable. |
| secret_access_key | AWS secret access key. | Required only if AWS credentials aren't otherwise set in the environment. | Value of AWS_SECRET_ACCESS_KEY environment variable. |
| region | AWS region to store the trust bundle. | Yes. | |
| trust_anchor_id | The AWS IAM Roles Anywhere trust anchor id of the trust anchor to which to put the trust bundle. | Yes. | |

## AWS IAM Permissions

The user identified by the configured credentials may need to have the `rolesanywhere:CreateTrustAnchor`, `rolesanywhere:UpdateTrustAnchor`, `rolesanywhere:ListTrustAnchors`, and `iam:CreateServiceLinkedRole` permissions. Note that these permissions aren't always required in order to perform a trust bundle update. Please see the [IAM Roles Anywhere API Reference](https://docs.aws.amazon.com/rolesanywhere/latest/APIReference/Welcome.html) for more details.
The user identified by the configured credentials needs to have `rolesanywhere:UpdateTrustAnchor` permissions.

## Sample configuration

Expand All @@ -25,7 +26,7 @@ The following configuration puts the local trust bundle contents into the `spire
BundlePublisher "aws_rolesanywhere_trustanchor" {
plugin_data {
region = "us-east-1"
trust_anchor_name = "spire-trust-anchor"
trust_anchor_id = "153d3e58-cab5-4a59-a0a1-3febad2937c4"
}
}
```
100 changes: 27 additions & 73 deletions pkg/server/plugin/bundlepublisher/awsrolesanywhere/awsrolesanywhere.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type Config struct {
AccessKeyID string `hcl:"access_key_id" json:"access_key_id"`
SecretAccessKey string `hcl:"secret_access_key" json:"secret_access_key"`
Region string `hcl:"region" json:"region"`
TrustAnchorName string `hcl:"trust_anchor_name" json:"trust_anchor_name"`
TrustAnchorID string `hcl:"trust_anchor_id" json:"trust_anchor_id"`
}

// Plugin is the main representation of this bundle publisher plugin.
Expand Down Expand Up @@ -86,8 +86,8 @@ func (p *Plugin) Configure(ctx context.Context, req *configv1.ConfigureRequest)
return &configv1.ConfigureResponse{}, nil
}

// PublishBundle puts the bundle in the first Roles Anywhere trust anchor
// found with the configured name. If one doesn't exist, it is created.
// PublishBundle puts the bundle in the Roles Anywhere trust anchor, with
// the configured id.
func (p *Plugin) PublishBundle(ctx context.Context, req *bundlepublisherv1.PublishBundleRequest) (*bundlepublisherv1.PublishBundleResponse, error) {
config, err := p.getConfig()
if err != nil {
Expand All @@ -106,82 +106,36 @@ func (p *Plugin) PublishBundle(ctx context.Context, req *bundlepublisherv1.Publi

formatter := bundleformat.NewFormatter(req.GetBundle())
bundleBytes, err := formatter.Format(bundleformat.PEM)
if err != nil {
return nil, status.Error(codes.Internal, "could not format bundle to PEM format")
}
bundleStr := string(bundleBytes)

// Check whether there already exists a trust anchor with the name requested
// If so, perform an update of its trust bundle
var trustAnchor rolesanywheretypes.TrustAnchorDetail
foundTrustAnchor := false
prevNextToken := ""
for ok := true; ok; {
// List trust anchors
listTrustAnchorsInput := rolesanywhere.ListTrustAnchorsInput{}
if prevNextToken != "" {
listTrustAnchorsInput.NextToken = &prevNextToken
}
listTrustAnchorsOutput, err := p.rolesAnywhereClient.ListTrustAnchors(ctx, &listTrustAnchorsInput)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list trust anchors: %v", err)
}

// Iterate through trust anchors in response
for _, curTrustAnchor := range listTrustAnchorsOutput.TrustAnchors {
if *curTrustAnchor.Name == config.TrustAnchorName {
trustAnchor = curTrustAnchor
foundTrustAnchor = true
break
}
}

if foundTrustAnchor {
break
}

if listTrustAnchorsOutput.NextToken == nil {
break
}
prevNextToken = *listTrustAnchorsOutput.NextToken
// To prevent flooding of the logs in the case that the bundle is
// too large.
if len(bundleStr) > 8000 {
return nil, status.Error(codes.InvalidArgument, "bundle too large")
}

trustAnchorArn := ""
if foundTrustAnchor {
// Update the trust anchor that was found
updateTrustAnchorInput := rolesanywhere.UpdateTrustAnchorInput{
TrustAnchorId: trustAnchor.TrustAnchorId,
Source: &rolesanywheretypes.Source{
SourceType: rolesanywheretypes.TrustAnchorTypeCertificateBundle,
SourceData: &rolesanywheretypes.SourceDataMemberX509CertificateData{
Value: bundleStr,
},
},
}
updateTrustAnchorOutput, err := p.rolesAnywhereClient.UpdateTrustAnchor(ctx, &updateTrustAnchorInput)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to update trust anchor: %v", err)
}
trustAnchorArn = *updateTrustAnchorOutput.TrustAnchor.TrustAnchorArn
} else {
// Create a new trust anchor, since an existing one with the requsted name couldn't be found
createTrustAnchorInput := rolesanywhere.CreateTrustAnchorInput{
Name: &config.TrustAnchorName,
Source: &rolesanywheretypes.Source{
SourceType: rolesanywheretypes.TrustAnchorTypeCertificateBundle,
SourceData: &rolesanywheretypes.SourceDataMemberX509CertificateData{
Value: bundleStr,
},
// Update the trust anchor that was found
updateTrustAnchorInput := rolesanywhere.UpdateTrustAnchorInput{
TrustAnchorId: &config.TrustAnchorID,
Source: &rolesanywheretypes.Source{
SourceType: rolesanywheretypes.TrustAnchorTypeCertificateBundle,
SourceData: &rolesanywheretypes.SourceDataMemberX509CertificateData{
Value: bundleStr,
},
Enabled: func() *bool { b := true; return &b }(),
}

createTrustAnchorOutput, err := p.rolesAnywhereClient.CreateTrustAnchor(ctx, &createTrustAnchorInput)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to create trust anchor: %v", err)
}
trustAnchorArn = *createTrustAnchorOutput.TrustAnchor.TrustAnchorArn
},
}
updateTrustAnchorOutput, err := p.rolesAnywhereClient.UpdateTrustAnchor(ctx, &updateTrustAnchorInput)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to update trust anchor: %v", err)
}
trustAnchorArn := *updateTrustAnchorOutput.TrustAnchor.TrustAnchorArn
trustAnchorName := *updateTrustAnchorOutput.TrustAnchor.Name

p.setBundle(req.GetBundle())
p.log.Debug("Trust anchor bundle updated", "ARN", trustAnchorArn)
p.log.Debug("Bundle published", "arn", trustAnchorArn, "trust_anchor_name", trustAnchorName)
return &bundlepublisherv1.PublishBundleResponse{}, nil
}

Expand Down Expand Up @@ -250,8 +204,8 @@ func parseAndValidateConfig(c string) (*Config, error) {
return nil, status.Error(codes.InvalidArgument, "configuration is missing the region")
}

if config.TrustAnchorName == "" {
return nil, status.Error(codes.InvalidArgument, "configuration is missing the trust anchor name")
if config.TrustAnchorID == "" {
return nil, status.Error(codes.InvalidArgument, "configuration is missing the trust anchor id")
}
return config, nil
}
Loading

0 comments on commit 7713757

Please sign in to comment.