Skip to content

Commit

Permalink
validate AWS credentials before sending any API calls; update documen…
Browse files Browse the repository at this point in the history
…tation

Signed-off-by: Rumen Vasilev <[email protected]>
  • Loading branch information
rumenvasilev committed Oct 21, 2024
1 parent ac29f35 commit 90a4e5a
Show file tree
Hide file tree
Showing 14 changed files with 290 additions and 95 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## dev (Unreleased)

## 0.1.2

FEATURES:
* validate AWS credentials before sending any API calls
* update documentation

## 0.1.1 (Unreleased)

FEATURES:
Expand Down
124 changes: 124 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Terraform Provider: FastSSM

The FastSSM provider was written to speed-up terraform runs across larger installations/usage, where AWS SSM parameter is employed. And so it handles only the lifecycle of AWS SSM parameter (both resource and data-source), but much faster. There's a limited set of attributes supported (omitted some of the metadata) in order to reduce the amount of expensive (latency, rate-limit) API calls, sometimes by more than 95%. There are no plans to extend it with support for any other AWS resources.

The ssm_parameter resource can be used to create a AWS SSM [parameter](docs/resources/parameter.md).

**THIS PROVIDER IS STILL EXPERIMENTAL AND IN ACTIVE DEVELOPMENT! USE AT YOUR OWN RISK!**

## Why write a separate provider?

Great question! Initial plan was to follow-up with some community ideas in terraform-provider-aws to improve the performance. However after reviewing the codebase (that's one of the first terraform proviers ever), I decided it would be much faster and easier to just write just this resource from scratch in a provider envelope, without the difficulty of maintaining full backward compatibility with every feature terraform-provider-aws had.

Starting fresh allowed the full adoption of the latest terraform-provider-framework, making it a lot simpler and easier to bootstrap a POC.

My tests so far have proven read operations (the aim of this optimization), with thousands of SSM parameters, have gone down from multiple minutes, down to seconds. And thus terraform plan (refresh) and terraform destroy commands have both benefitted greatly. The refresh is the most abused operation with existing systems.

## Documentation, questions and discussions

Official documentation on how to use this provider can be found on the
[Terraform Registry](https://registry.terraform.io/providers/rumenvasilev/fastssm/latest/docs).
In case of specific questions or discussions, please use the
[GitHub issues here](https://github.com/rumenvasilev/terraform-provider-fastssm/issues).

We also provide:

* [Support](.github/SUPPORT.md) page for help when using the provider
* [Contributing](.github/CONTRIBUTING.md) guidelines in case you want to help this project

The remainder of this document will focus on the development aspects of the provider.

## Requirements

* [Terraform](https://www.terraform.io/downloads) (>= 0.12)
* [Go](https://go.dev/doc/install) (1.23)
* [GNU Make](https://www.gnu.org/software/make/)
* [golangci-lint](https://golangci-lint.run/usage/install/#local-installation) (optional)

## Development

### Building

1. `git clone` this repository and `cd` into its directory
2. `make build` will trigger the Golang build

The provided `GNUmakefile` defines additional commands generally useful during development,
like for running tests, generating documentation, code formatting and linting.
Taking a look at it's content is recommended.

### Testing

In order to test the provider, you can run

* `make test` to run provider tests
* `make testacc` to run provider acceptance tests

It's important to note that acceptance tests (`testacc`) will actually spawn
`terraform` and the provider. Read more about they work on the
[official page](https://www.terraform.io/plugin/sdkv2/testing/acceptance-tests).

### Generating documentation

This provider uses [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs/)
to generate documentation and store it in the `docs/` directory.
Once a release is cut, the Terraform Registry will download the documentation from `docs/`
and associate it with the release version. Read more about how this works on the
[official page](https://www.terraform.io/registry/providers/docs).

Use `make generate` to ensure the documentation is regenerated with any changes.

### Using a development build

If [running tests and acceptance tests](#testing) isn't enough, it's possible to set up a local terraform configuration
to use a development builds of the provider. This can be achieved by leveraging the Terraform CLI
[configuration file development overrides](https://www.terraform.io/cli/config/config-file#development-overrides-for-provider-developers).

First, use `make install` to place a fresh development build of the provider in your [`${GOBIN}`](https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies) (defaults to `${GOPATH}/bin` or `${HOME}/go/bin` if `${GOPATH}` is not set). Repeat
this every time you make changes to the provider locally.

Then, in your `${HOME}/.terraformrc` (Unix) / `%APPDATA%\terraform.rc` (Windows), a `provider_installation` that contains
the following `dev_overrides`:

```hcl
provider_installation {
dev_overrides {
"rumenvasilev/fastssm" = "${GOBIN}" //< replace `${GOBIN}` with the actual path on your system
}
direct {}
}
```

Note that it's also possible to use a dedicated Terraform configuration file and invoke `terraform` while setting
the environment variable `TF_CLI_CONFIG_FILE=my_terraform_config_file`.

Once the `dev_overrides` are in place, any local execution of `terraform plan` and `terraform apply` will
use the version of the provider found in the given `${GOBIN}` directory,
instead of the one indicated in your terraform configuration.

### Testing GitHub Actions

This project uses [GitHub Actions](https://docs.github.com/en/actions/automating-builds-and-tests) to realize its CI.

Sometimes it might be helpful to locally reproduce the behaviour of those actions,
and for this we use [act](https://github.com/nektos/act). Once installed, you can _simulate_ the actions executed
when opening a PR with:

```shell
# List of workflows for the 'pull_request' action
$ act -l pull_request

# Execute the workflows associated with the `pull_request' action
$ act pull_request
```

## Releasing

The release process is automated via GitHub Actions, and it's defined in the Workflow
[release.yml](./.github/workflows/release.yml).

Each release is cut by pushing a [semantically versioned](https://semver.org/) tag to the default branch.

## License

[Apache 2.0](./LICENSE)
17 changes: 10 additions & 7 deletions docs/data-sources/parameter.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@ data "fastssm_parameter" "example" {
<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) Name of the parameter.

### Optional

- `insecure_value` (String)
- `value` (String, Sensitive)
- `with_decryption` (Boolean)
- `with_decryption` (Boolean) Whether to return decrypted `SecureString` value. Defaults to `true`.

### Read-Only

- `arn` (String)
- `name` (String)
- `type` (String)
- `version` (Number)
- `arn` (String) ARN of the parameter.
- `insecure_value` (String) Value of the parameter. **Use caution:** This value is never marked as sensitive.
- `type` (String) Type of the parameter. Valid types are `String`, `StringList` and `SecureString`.
- `value` (String, Sensitive) Value of the parameter. This value is always marked as sensitive in the Terraform plan output, regardless of `type`. In Terraform CLI version 0.15 and later, this may require additional configuration handling for certain scenarios. For more information, see the [Terraform v0.15 Upgrade Guide](https://www.terraform.io/upgrade-guides/0-15.html#sensitive-output-values).
- `version` (Number) Version of the parameter.
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
page_title: "fastssm Provider"
subcategory: ""
description: |-
~> Note: When you start having thousands of SSM parameters, you begin to notice quite some slowness of terraform. It's highly likely that you've exhausted the rate limit of AWS SSM API. Even if you upgrade the limit, that only applies for GetParameter calls. In the official AWS provider, for each GetParameter call, there's an additional DescribeParameters call made. That's where the bottleneck is. This provider eliminates >90% of these rate-limited calls, by not doing them in the first place. It's at the expense of not supporting all the metadata, but that should be a fair trade-off, considering you can still use SSM parameter store, fast.
---

# fastssm Provider


~> **Note:** When you start having thousands of SSM parameters, you begin to notice quite some slowness of terraform. It's highly likely that you've exhausted the rate limit of AWS SSM API. Even if you upgrade the limit, that only applies for GetParameter calls. In the official AWS provider, for each GetParameter call, there's an additional DescribeParameters call made. That's where the bottleneck is. This provider eliminates >90% of these rate-limited calls, by not doing them in the first place. It's at the expense of not supporting all the metadata, but that should be a fair trade-off, considering you can still use SSM parameter store, fast.

## Example Usage

Expand Down
35 changes: 23 additions & 12 deletions docs/resources/parameter.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,54 @@
page_title: "fastssm_parameter Resource - fastssm"
subcategory: ""
description: |-
SSM Parameter resource
~> Note: this is a slimmer and faster version, but doesn't include all the metadata you would normally enjoy with the official terraform-provider-aws. If performance is an issue, this should be a drop-in replacement for ssm_parameter resource from the official aws provider.
---

# fastssm_parameter (Resource)

SSM Parameter resource
~> **Note:** this is a slimmer and faster version, but doesn't include all the metadata you would normally enjoy with the official terraform-provider-aws. If performance is an issue, this should be a drop-in replacement for ssm_parameter resource from the official aws provider.

## Example Usage

```terraform
### Basic example
resource "fastssm_parameter" "example" {
name = "some-ssm-parameter"
type = "String"
insecure_value = "some-insecure-value"
description = "An example description"
}
### Encrypted string with default KMS key
resource "fastssm_parameter" "secure" {
name = "some-encrypted-ssm-parameter"
type = "SecureString"
value = "some-secure-value"
description = "An example description"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String)
- `type` (String)
- `name` (String) Name of the parameter. If the name contains a path (e.g., any forward slashes (`/`)), it must be fully qualified with a leading forward slash (`/`). For additional requirements and constraints, see the [AWS SSM User Guide](https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-parameter-name-constraints.html).
- `type` (String) Type of the parameter. Valid types are `String`, `StringList` and `SecureString`.

### Optional

- `allowed_pattern` (String)
- `arn` (String)
- `data_type` (String)
- `description` (String)
- `insecure_value` (String)
- `overwrite` (Boolean, Deprecated)
- `allowed_pattern` (String) Regular expression used to validate the parameter value.
- `arn` (String) ARN of the parameter.
- `data_type` (String) Data type of the parameter. Valid values: `text`, `aws:ssm:integration` and `aws:ec2:image` for AMI format, see the [Native parameter support for Amazon Machine Image IDs](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-ec2-aliases.html)
- `description` (String) Description of the parameter.
- `insecure_value` (String) Value of the parameter. **Use caution:** This value is _never_ marked as sensitive in the Terraform plan output. This argument is not valid with a `type` of `SecureString`.
- `overwrite` (Boolean, Deprecated) Overwrite an existing parameter. If not specified, defaults to `false` if the resource has not been created by Terraform to avoid overwrite of existing resource, and will default to `true` otherwise (Terraform lifecycle rules should then be used to manage the update behavior).
- `tags` (Map of String, Deprecated) UNSUPPORTED. This feature is intentionally unavailable for performance reasons. You can still pass input data to it for backwards compatibility, but it will not be reflected in the ssm_parameter resource in AWS.
- `value` (String, Sensitive)
- `value` (String, Sensitive) Value of the parameter. This value is always marked as sensitive in the Terraform plan output, regardless of `type`. In Terraform CLI version 0.15 and later, this may require additional configuration handling for certain scenarios. For more information, see the [Terraform v0.15 Upgrade Guide](https://www.terraform.io/upgrade-guides/0-15.html#sensitive-output-values).

### Read-Only

- `version` (Number)
- `version` (Number) Version of the parameter.
11 changes: 11 additions & 0 deletions examples/resources/fastssm_parameter/resource.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
### Basic example

resource "fastssm_parameter" "example" {
name = "some-ssm-parameter"
type = "String"
insecure_value = "some-insecure-value"
description = "An example description"
}

### Encrypted string with default KMS key

resource "fastssm_parameter" "secure" {
name = "some-encrypted-ssm-parameter"
type = "SecureString"
value = "some-secure-value"
description = "An example description"
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/aws/aws-sdk-go-v2 v1.32.2
github.com/aws/aws-sdk-go-v2/config v1.27.43
github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2
github.com/aws/smithy-go v1.22.0
github.com/hashicorp/terraform-plugin-framework v1.12.0
github.com/hashicorp/terraform-plugin-framework-validators v0.13.0
Expand All @@ -29,7 +30,6 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
Expand Down
53 changes: 0 additions & 53 deletions internal/provider/example_resource_test.go

This file was deleted.

19 changes: 12 additions & 7 deletions internal/provider/parameter_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,11 @@ func (d *ParameterDataSource) Schema(ctx context.Context, req datasource.SchemaR
Attributes: map[string]schema.Attribute{
names.AttrARN: schema.StringAttribute{
// Optional: true,
Computed: true,
Computed: true,
Description: "ARN of the parameter.",
},
"insecure_value": schema.StringAttribute{
Optional: true,
// Computed: true,
// Sensitive: true,
Computed: true,
Validators: []validator.String{
stringvalidator.All(
stringvalidator.ConflictsWith(path.Expressions{
Expand All @@ -70,23 +69,26 @@ func (d *ParameterDataSource) Schema(ctx context.Context, req datasource.SchemaR
// PlanModifiers: []planmodifier.String{
// SyncAttributePlanModifier("value"),
// },
Description: "Value of the parameter. **Use caution:** This value is never marked as sensitive.",
},
names.AttrName: schema.StringAttribute{
Computed: true,
Required: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// },
Description: "Name of the parameter.",
},
names.AttrType: schema.StringAttribute{
// Required: true,
Computed: true,
// Validators: []validator.String{
// stringvalidator.OneOf("String", "StringList", "SecureString"),
// }, // awstypes.ParameterType.Values()
Description: "Type of the parameter. Valid types are `String`, `StringList` and `SecureString`.",
},
names.AttrValue: schema.StringAttribute{
Sensitive: true,
Optional: true,
Computed: true,
// Computed: true,
// https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator#ExactlyOneOf
Validators: []validator.String{
Expand All @@ -96,14 +98,17 @@ func (d *ParameterDataSource) Schema(ctx context.Context, req datasource.SchemaR
}...),
// dependentParameterValidator{dependentParamName: "type", requiredValue: []string{"SecureString"}},
)},
Description: "Value of the parameter. This value is always marked as sensitive in the Terraform plan output, regardless of `type`. In Terraform CLI version 0.15 and later, this may require additional configuration handling for certain scenarios. For more information, see the [Terraform v0.15 Upgrade Guide](https://www.terraform.io/upgrade-guides/0-15.html#sensitive-output-values).",
},
names.AttrVersion: schema.Int64Attribute{
Computed: true,
Computed: true,
Description: "Version of the parameter.",
},
"with_decryption": schema.BoolAttribute{
Optional: true,
// TODO need to set this to default = true
// Default: true,
Description: "Whether to return decrypted `SecureString` value. Defaults to `true`.",
},
},
}
Expand Down
Loading

0 comments on commit 90a4e5a

Please sign in to comment.