Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions internal/conns/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type Config struct {
TokenBucketRateLimiterCapacity int
UseDualStackEndpoint bool
UseFIPSEndpoint bool
UserAgent awsbase.UserAgentProducts
}

// ConfigureProvider configures the provided provider Meta (instance data).
Expand Down Expand Up @@ -112,6 +113,7 @@ func (c *Config) ConfigureProvider(ctx context.Context, client *AWSClient) (*AWS
TokenBucketRateLimiterCapacity: c.TokenBucketRateLimiterCapacity,
UseDualStackEndpoint: c.UseDualStackEndpoint,
UseFIPSEndpoint: c.UseFIPSEndpoint,
UserAgent: c.UserAgent,
}

if c.CustomCABundle != "" {
Expand Down
73 changes: 73 additions & 0 deletions internal/provider/framework/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/function"
"github.com/hashicorp/terraform-plugin-framework/list"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/metaschema"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
resourceschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
Expand All @@ -49,6 +50,7 @@ var (
_ provider.ProviderWithFunctions = &frameworkProvider{}
_ provider.ProviderWithEphemeralResources = &frameworkProvider{}
_ provider.ProviderWithListResources = &frameworkProvider{}
_ provider.ProviderWithMetaSchema = &frameworkProvider{}
)

type frameworkProvider struct {
Expand Down Expand Up @@ -339,7 +341,78 @@ func (*frameworkProvider) Schema(ctx context.Context, request provider.SchemaReq
},
},
},
"user_agent": schema.ListNestedBlock{
Description: "Product details to append to the User-Agent string sent in all AWS API calls.",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"comment": schema.StringAttribute{
Optional: true,
Description: "Comment describing any additional product details.",
},
"product_name": schema.StringAttribute{
Required: true,
Description: "Product name.",
},
"product_version": schema.StringAttribute{
Optional: true,
Description: "Product version. Optional, and should only be set when `product_name` is set.",
},
},
},
},
},
}
}

func (p *frameworkProvider) MetaSchema(ctx context.Context, req provider.MetaSchemaRequest, resp *provider.MetaSchemaResponse) {
resp.Schema = metaschema.Schema{
Attributes: map[string]metaschema.Attribute{
"user_agent": metaschema.ListNestedAttribute{
Description: "Product details to append to the User-Agent string sent in all AWS API calls.",
Optional: true,
NestedObject: metaschema.NestedAttributeObject{
Attributes: map[string]metaschema.Attribute{
"comment": schema.StringAttribute{
Description: "Comment describing any additional product details.",
Optional: true,
},
"product_name": schema.StringAttribute{
Description: "Product name.",
Required: true,
},
"product_version": schema.StringAttribute{
Description: "Product version. Optional, and should only be set when `product_name` is set.",
Optional: true,
},
},
},
},
},

// TODO
// metaschema.Schema does not support a Blocks field. Can we mux this if we're on protocol V5?
//
// Blocks: map[string]schema.Block{
// "user_agent": schema.ListNestedBlock{
// Description: "Product details to append to the User-Agent string sent in all AWS API calls.",
// NestedObject: schema.NestedBlockObject{
// Attributes: map[string]schema.Attribute{
// "comment": schema.StringAttribute{
// Optional: true,
// Description: "Comment describing any additional product details.",
// },
// "product_name": schema.StringAttribute{
// Required: true,
// Description: "Product name.",
// },
// "product_version": schema.StringAttribute{
// Optional: true,
// Description: "Product version. Optional, and should only be set when `product_name` is set.",
// },
// },
// },
// },
// },
}
}

Expand Down
52 changes: 52 additions & 0 deletions internal/provider/sdkv2/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,58 @@ func NewProvider(ctx context.Context) (*schema.Provider, error) {
Optional: true,
Description: "Resolve an endpoint with FIPS capability",
},
"user_agent": {
Type: schema.TypeList,
Optional: true,
Description: "Product details to append to the User-Agent string sent in all AWS API calls.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"comment": {
Type: schema.TypeString,
Optional: true,
Description: "Comment describing any additional product details.",
},
"product_name": {
Type: schema.TypeString,
Required: true,
Description: "Product name.",
},
"product_version": {
Type: schema.TypeString,
Optional: true,
Description: "Product version. Optional, and should only be set when `product_name` is set.",
},
},
},
},
},

// ProviderMetaSchema enables module-scoped User-Agent modifications
ProviderMetaSchema: map[string]*schema.Schema{
"user_agent": {
Type: schema.TypeList,
Optional: true,
Description: "Product details to append to the User-Agent string sent in all AWS API calls.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"comment": {
Type: schema.TypeString,
Optional: true,
Description: "Comment describing any additional product details.",
},
"product_name": {
Type: schema.TypeString,
Required: true,
Description: "Product name.",
},
"product_version": {
Type: schema.TypeString,
Optional: true,
Description: "Product version. Optional, and should only be set when `product_name` is set.",
},
},
},
},
},

// Data sources and resources implemented using Terraform Plugin SDK
Expand Down
49 changes: 48 additions & 1 deletion website/docs/index.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,40 @@ provider "aws" {
```ini
[profile customprofile]
credential_process = custom-process --username jdoe

```

### Module-scoped User-Agent Information with `provider_meta`

The AWS provider supports sending provider metadata via the [`provider_meta` block](https://developer.hashicorp.com/terraform/internals/provider-meta).
This block allows module authors to provide additional information in the `User-Agent` header, scoped only to resources defined in a given module.

For example, the following `terraform` block can be used to append additional User-Agent details.

```terraform
terraform {
required_providers {
awscc = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}

provider_meta "aws" {
user_agent = [
{
product_name = "example-demo"
product_version = "0.0.1"
comment = "a demo module"
},
]
}
}
```

Note that `provider_meta` is defined within the `terraform` block.
The `provider` block is inherited from the root module.

## AWS Configuration Reference

|Setting|Provider|[Environment Variable][envvars]|[Shared Config][config]|
Expand Down Expand Up @@ -301,12 +333,27 @@ See the assume role documentation [section on web identities](https://docs.aws.a

## Custom User-Agent Information

By default, the underlying AWS client used by the Terraform AWS Provider creates requests with User-Agent headers including information about Terraform and AWS SDK for Go versions. To provide additional information in the User-Agent headers, the `TF_APPEND_USER_AGENT` environment variable can be set and its value will be directly added to HTTP requests. E.g.,
By default, the underlying AWS client used by the Terraform AWS Provider creates requests with User-Agent headers including information about Terraform and AWS SDK for Go versions.
To provide additional information in the User-Agent headers, set the `TF_APPEND_USER_AGENT` environment variable, or use the `user_agent` block.

When using the environment variable, the value will be directly appended to the User-Agent header.
For example,

```console
% export TF_APPEND_USER_AGENT="JenkinsAgent/i-12345678 BuildID/1234 (Optional Extra Information)"
```

When using the `user_agent` block, the components will be parsed and appended to the User-Agent in the form `{product_name}/{product_version} ({comment})`.
For example, the configuration below would append `example-demo/0.0.1 (a demo module)`.

```terraform
user_agent {
product_name = "example-demo"
product_version = "0.0.1"
comment = "a demo module"
}
```

## Argument Reference

In addition to [generic `provider` arguments](https://www.terraform.io/docs/configuration/providers.html)
Expand Down
Loading