Skip to content

Commit fdaaba7

Browse files
committed
Add AWS CLI module for Coder Registry
- Installs AWS CLI v2 in Coder workspaces - Supports x86_64 and ARM64 architectures with auto-detection - Allows version pinning or installs latest version - Optional GPG signature verification for security - Idempotent installation (skips if already installed) - Supports custom installation directories - Includes comprehensive tests (Terraform + TypeScript) - Full documentation with multiple usage examples
1 parent 583918b commit fdaaba7

File tree

5 files changed

+556
-0
lines changed

5 files changed

+556
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
---
2+
display_name: AWS CLI
3+
description: Install the AWS Command Line Interface in your workspace
4+
icon: ../../../../.icons/aws.svg
5+
verified: false
6+
tags: [aws, cli, tools]
7+
---
8+
9+
# AWS CLI
10+
11+
Automatically install the [AWS Command Line Interface (CLI)](https://aws.amazon.com/cli/) in a Coder workspace. The AWS CLI is a unified tool to manage AWS services from the command line.
12+
13+
```tf
14+
module "aws-cli" {
15+
count = data.coder_workspace.me.start_count
16+
source = "registry.coder.com/coder/aws-cli/coder"
17+
version = "1.0.0"
18+
agent_id = coder_agent.example.id
19+
}
20+
```
21+
22+
## Features
23+
24+
- ✅ Supports both x86_64 and ARM64 (aarch64) architectures
25+
- ✅ Automatic architecture detection
26+
- ✅ Install latest version or pin to a specific version
27+
- ✅ Optional GPG signature verification
28+
- ✅ Idempotent - skips installation if already present
29+
- ✅ Supports custom installation directories
30+
31+
## Examples
32+
33+
### Basic Installation (Latest Version)
34+
35+
Install the latest version of AWS CLI:
36+
37+
```tf
38+
module "aws-cli" {
39+
count = data.coder_workspace.me.start_count
40+
source = "registry.coder.com/coder/aws-cli/coder"
41+
version = "1.0.0"
42+
agent_id = coder_agent.example.id
43+
}
44+
```
45+
46+
### Pin to Specific Version
47+
48+
Install a specific version of AWS CLI for consistency across your team:
49+
50+
```tf
51+
module "aws-cli" {
52+
count = data.coder_workspace.me.start_count
53+
source = "registry.coder.com/coder/aws-cli/coder"
54+
version = "1.0.0"
55+
agent_id = coder_agent.example.id
56+
57+
# Pin to AWS CLI version 2.15.0
58+
aws_cli_version = "2.15.0"
59+
}
60+
```
61+
62+
Note: Find available versions in the [AWS CLI v2 Changelog](https://github.com/aws/aws-cli/blob/v2/CHANGELOG.rst).
63+
64+
### Custom Installation Directory
65+
66+
Install AWS CLI to a custom directory (useful when you don't have sudo access):
67+
68+
```tf
69+
module "aws-cli" {
70+
count = data.coder_workspace.me.start_count
71+
source = "registry.coder.com/coder/aws-cli/coder"
72+
version = "1.0.0"
73+
agent_id = coder_agent.example.id
74+
install_directory = "/home/coder/.local"
75+
}
76+
```
77+
78+
### Verify GPG Signature
79+
80+
Enable GPG signature verification for enhanced security:
81+
82+
```tf
83+
module "aws-cli" {
84+
count = data.coder_workspace.me.start_count
85+
source = "registry.coder.com/coder/aws-cli/coder"
86+
version = "1.0.0"
87+
agent_id = coder_agent.example.id
88+
verify_signature = true
89+
}
90+
```
91+
92+
### Specify Architecture
93+
94+
Explicitly set the architecture (usually auto-detected):
95+
96+
```tf
97+
module "aws-cli" {
98+
count = data.coder_workspace.me.start_count
99+
source = "registry.coder.com/coder/aws-cli/coder"
100+
version = "1.0.0"
101+
agent_id = coder_agent.example.id
102+
architecture = "aarch64" # or "x86_64"
103+
}
104+
```
105+
106+
## Configuration
107+
108+
After installing AWS CLI, users will need to configure their AWS credentials. This can be done using:
109+
110+
```bash
111+
aws configure
112+
```
113+
114+
Or by setting environment variables:
115+
116+
```bash
117+
export AWS_ACCESS_KEY_ID="your-access-key-id"
118+
export AWS_SECRET_ACCESS_KEY="your-secret-access-key"
119+
export AWS_DEFAULT_REGION="us-east-1"
120+
```
121+
122+
For more information, see the [AWS CLI Configuration Guide](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html).
123+
124+
## Variables
125+
126+
| Name | Description | Default | Required |
127+
| ------------------- | -------------------------------------------------------------------------------------------- | -------------- | -------- |
128+
| `agent_id` | The ID of a Coder agent | - | Yes |
129+
| `aws_cli_version` | The version of AWS CLI to install (leave empty for latest) | `""` | No |
130+
| `install_directory` | The directory to install AWS CLI to | `/usr/local` | No |
131+
| `architecture` | The architecture to install AWS CLI for (`x86_64` or `aarch64`, empty for auto-detection) | `""` | No |
132+
| `verify_signature` | Whether to verify the GPG signature of the downloaded installer | `false` | No |
133+
134+
## Outputs
135+
136+
| Name | Description |
137+
| ----------------- | ------------------------------------------------------------------------------------ |
138+
| `aws_cli_version` | The version of AWS CLI that was installed (or 'latest' if no version was specified) |
139+
140+
## Requirements
141+
142+
- Linux operating system (x86_64 or ARM64)
143+
- `curl` for downloading the installer
144+
- `unzip` for extracting the installer
145+
- `sudo` access (if installing to system directories like `/usr/local`)
146+
- Optional: `gpg` (if using signature verification)
147+
148+
## Supported Platforms
149+
150+
- Amazon Linux 1 & 2
151+
- CentOS
152+
- Fedora
153+
- Ubuntu
154+
- Debian
155+
- Any Linux distribution with glibc, groff, and less
156+
157+
## Notes
158+
159+
- The module is idempotent - if AWS CLI is already installed with the correct version, it will skip the installation
160+
- When no version is specified, the latest version will be installed
161+
- The installer automatically creates a symlink at `/usr/local/bin/aws` (or `$INSTALL_DIRECTORY/bin/aws`)
162+
- Architecture is automatically detected based on `uname -m` if not explicitly specified
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
run "required_vars" {
2+
command = plan
3+
4+
variables {
5+
agent_id = "test-agent-id"
6+
}
7+
}
8+
9+
run "with_version" {
10+
command = plan
11+
12+
variables {
13+
agent_id = "test-agent-id"
14+
aws_cli_version = "2.15.0"
15+
}
16+
17+
assert {
18+
condition = resource.coder_script.aws-cli.script != ""
19+
error_message = "coder_script must have a valid script"
20+
}
21+
}
22+
23+
run "custom_install_directory" {
24+
command = plan
25+
26+
variables {
27+
agent_id = "test-agent-id"
28+
install_directory = "/home/coder/.local"
29+
}
30+
31+
assert {
32+
condition = resource.coder_script.aws-cli.script != ""
33+
error_message = "coder_script must have a valid script"
34+
}
35+
}
36+
37+
run "architecture_validation_x86_64" {
38+
command = plan
39+
40+
variables {
41+
agent_id = "test-agent-id"
42+
architecture = "x86_64"
43+
}
44+
45+
assert {
46+
condition = resource.coder_script.aws-cli.script != ""
47+
error_message = "coder_script must have a valid script"
48+
}
49+
}
50+
51+
run "architecture_validation_aarch64" {
52+
command = plan
53+
54+
variables {
55+
agent_id = "test-agent-id"
56+
architecture = "aarch64"
57+
}
58+
59+
assert {
60+
condition = resource.coder_script.aws-cli.script != ""
61+
error_message = "coder_script must have a valid script"
62+
}
63+
}
64+
65+
run "architecture_validation_invalid" {
66+
command = plan
67+
68+
variables {
69+
agent_id = "test-agent-id"
70+
architecture = "invalid"
71+
}
72+
73+
expect_failures = [
74+
var.architecture
75+
]
76+
}
77+
78+
run "verify_signature" {
79+
command = plan
80+
81+
variables {
82+
agent_id = "test-agent-id"
83+
verify_signature = true
84+
}
85+
86+
assert {
87+
condition = resource.coder_script.aws-cli.script != ""
88+
error_message = "coder_script must have a valid script"
89+
}
90+
}
91+
92+
run "output_version_default" {
93+
command = plan
94+
95+
variables {
96+
agent_id = "test-agent-id"
97+
}
98+
99+
assert {
100+
condition = output.aws_cli_version == "latest"
101+
error_message = "output version should be 'latest' when no version is specified"
102+
}
103+
}
104+
105+
run "output_version_specified" {
106+
command = plan
107+
108+
variables {
109+
agent_id = "test-agent-id"
110+
aws_cli_version = "2.15.0"
111+
}
112+
113+
assert {
114+
condition = output.aws_cli_version == "2.15.0"
115+
error_message = "output version should match the specified version"
116+
}
117+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { describe, expect, it } from "bun:test";
2+
import {
3+
runTerraformApply,
4+
runTerraformInit,
5+
testRequiredVariables,
6+
} from "~test";
7+
8+
describe("aws-cli", async () => {
9+
await runTerraformInit(import.meta.dir);
10+
11+
testRequiredVariables(import.meta.dir, {
12+
agent_id: "foo",
13+
});
14+
15+
it("default output version is 'latest'", async () => {
16+
const state = await runTerraformApply(import.meta.dir, {
17+
agent_id: "foo",
18+
});
19+
expect(state.outputs.aws_cli_version.value).toBe("latest");
20+
});
21+
22+
it("output version matches specified version", async () => {
23+
const version = "2.15.0";
24+
const state = await runTerraformApply(import.meta.dir, {
25+
agent_id: "foo",
26+
aws_cli_version: version,
27+
});
28+
expect(state.outputs.aws_cli_version.value).toBe(version);
29+
});
30+
31+
it("accepts custom install directory", async () => {
32+
const state = await runTerraformApply(import.meta.dir, {
33+
agent_id: "foo",
34+
install_directory: "/home/coder/.local",
35+
});
36+
expect(state.resources).toHaveLength(1);
37+
});
38+
39+
it("accepts architecture parameter", async () => {
40+
const state = await runTerraformApply(import.meta.dir, {
41+
agent_id: "foo",
42+
architecture: "x86_64",
43+
});
44+
expect(state.resources).toHaveLength(1);
45+
});
46+
47+
it("accepts verify_signature parameter", async () => {
48+
const state = await runTerraformApply(import.meta.dir, {
49+
agent_id: "foo",
50+
verify_signature: "true",
51+
});
52+
expect(state.resources).toHaveLength(1);
53+
});
54+
});
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
terraform {
2+
required_version = ">= 1.0"
3+
4+
required_providers {
5+
coder = {
6+
source = "coder/coder"
7+
version = ">= 2.5"
8+
}
9+
}
10+
}
11+
12+
variable "agent_id" {
13+
type = string
14+
description = "The ID of a Coder agent."
15+
}
16+
17+
variable "aws_cli_version" {
18+
type = string
19+
description = "The version of AWS CLI to install. Leave empty for latest."
20+
default = ""
21+
}
22+
23+
variable "install_directory" {
24+
type = string
25+
description = "The directory to install AWS CLI to."
26+
default = "/usr/local"
27+
}
28+
29+
variable "architecture" {
30+
type = string
31+
description = "The architecture to install AWS CLI for. Valid values are 'x86_64' and 'aarch64'. Leave empty for auto-detection."
32+
default = ""
33+
validation {
34+
condition = var.architecture == "" || var.architecture == "x86_64" || var.architecture == "aarch64"
35+
error_message = "The 'architecture' variable must be one of: '', 'x86_64', 'aarch64'."
36+
}
37+
}
38+
39+
variable "verify_signature" {
40+
type = bool
41+
description = "Whether to verify the GPG signature of the downloaded installer."
42+
default = false
43+
}
44+
45+
resource "coder_script" "aws-cli" {
46+
agent_id = var.agent_id
47+
display_name = "AWS CLI"
48+
icon = "/icon/aws.svg"
49+
script = templatefile("${path.module}/run.sh", {
50+
VERSION : var.aws_cli_version,
51+
INSTALL_DIRECTORY : var.install_directory,
52+
ARCHITECTURE : var.architecture,
53+
VERIFY_SIGNATURE : var.verify_signature
54+
})
55+
run_on_start = true
56+
}
57+
58+
output "aws_cli_version" {
59+
description = "The version of AWS CLI that was installed (or 'latest' if no version was specified)."
60+
value = var.aws_cli_version != "" ? var.aws_cli_version : "latest"
61+
}

0 commit comments

Comments
 (0)