Skip to content

Commit a3bec7e

Browse files
committed
feat(okms): add datasource and resource okms_secret
1 parent b9b2904 commit a3bec7e

File tree

12 files changed

+2345
-0
lines changed

12 files changed

+2345
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ In order to run the full suite of Acceptance tests you will need to have the fol
119119
- a [Load Balancer](https://www.ovh.ie/solutions/load-balancer/)
120120
- a registered [Domain](https://www.ovh.ie/domains/)
121121
- a [Cloud Project](https://www.ovh.ie/public-cloud/instances/)
122+
- a [KMS](https://www.ovhcloud.com/en-gb/identity-security-operations/key-management-service/)
122123

123124
You will also need to setup your [OVH API](https://api.ovh.com) credentials. (see [documentation](https://www.terraform.io/docs/providers/ovh/index.html#configuration-reference))
124125

@@ -158,6 +159,7 @@ export OVH_DOMAIN_NS3_HOST_TEST="..."
158159
export OVH_DOMAIN_DS_RECORD_ALGORITHM_TEST="..."
159160
export OVH_DOMAIN_DS_RECORD_PUBLIC_KEY_TEST="..."
160161
export OVH_DOMAIN_DS_RECORD_TAG_TEST="..."
162+
export OVH_OKMS="..."
161163

162164
$ make testacc
163165
```

docs/data-sources/okms_secret.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
subcategory : "Key Management Service (KMS)"
3+
---
4+
5+
# ovh_okms_secret (Data Source)
6+
7+
Retrieves metadata (and optionally the payload) of a secret stored in OVHcloud KMS.
8+
9+
> WARNING: If `include_data = true` the secret value is stored in cleartext (JSON) in the Terraform state file. Marked **Sensitive** only hides it from CLI output. If you use this option it is recommended to protect your state with encryption and access controls.
10+
11+
## Example Usage
12+
13+
Get the latest secret version (metadata only):
14+
15+
```terraform
16+
data "ovh_okms_secret" "latest" {
17+
okms_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
18+
path = "app/api_credentials"
19+
}
20+
```
21+
22+
Get the latest secret version including its data:
23+
24+
```terraform
25+
data "ovh_okms_secret" "latest_with_data" {
26+
okms_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
27+
path = "app/api_credentials"
28+
include_data = true
29+
}
30+
31+
locals {
32+
secret_obj = jsondecode(data.ovh_okms_secret.latest_with_data.data)
33+
}
34+
35+
output "api_key" {
36+
value = local.secret_obj.api_key
37+
sensitive = true
38+
}
39+
```
40+
41+
Get a specific version including its payload:
42+
43+
```terraform
44+
data "ovh_okms_secret" "v3" {
45+
okms_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
46+
path = "app/api_credentials"
47+
version = 3
48+
include_data = true
49+
}
50+
```
51+
52+
## Argument Reference
53+
54+
The following arguments are supported:
55+
56+
### Required
57+
58+
- `okms_id` (String) OKMS service ID that owns the secret.
59+
- `path` (String) Secret path (identifier within the OKMS instance).
60+
61+
### Optional
62+
63+
- `version` (Number) Specific version to retrieve. If omitted, the latest (current) version is selected.
64+
- `include_data` (Boolean) If true, retrieves the secret payload (`data` attribute). Defaults to false. When false only metadata is returned.
65+
66+
## Attributes Reference (Read-Only)
67+
68+
In addition to the arguments above, the following attributes are exported:
69+
70+
- `version` (Number) The resolved version number (requested or current latest).
71+
- `data` (String, Sensitive) Raw JSON secret payload (present only if `include_data` is true).
72+
- `metadata` (Block) Secret metadata:
73+
- `cas_required` (Boolean)
74+
- `created_at` (String)
75+
- `updated_at` (String)
76+
- `current_version` (Number)
77+
- `oldest_version` (Number)
78+
- `max_versions` (Number)
79+
- `deactivate_version_after` (String)
80+
- `custom_metadata` (Map of String)
81+
- `iam` (Block) IAM resource metadata:
82+
- `display_name` (String)
83+
- `id` (String)
84+
- `tags` (Map of String)
85+
- `urn` (String)
86+
87+
## Behavior & Notes
88+
89+
- The `data` attribute retains the raw JSON returned by the API. Use `jsondecode()` to work with individual keys.
90+
- Changing only `include_data` (true -> false) will cause the `data` attribute to become null in subsequent refreshes (state no longer holds the payload).

docs/resources/okms_secret.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
2+
---
3+
subcategory : "Key Management Service (KMS)"
4+
---
5+
6+
# ovh_okms_secret (Resource)
7+
8+
Manages a secret stored in OVHcloud KMS.
9+
10+
> WARNING: `version.data` is marked **Sensitive** but still ends up in the state file. To mitigate that, it is recommended to protect your state with encryption and access controls. Avoid committing it to source control.
11+
12+
## Example Usage
13+
14+
Create a secret whose value is a JSON object. Use `jsonencode()` to produce a deterministic JSON string (ordering/whitespace) to minimize diffs.
15+
16+
```terraform
17+
resource "ovh_okms_secret" "example" {
18+
okms_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
19+
path = "app/api_credentials"
20+
21+
metadata = {
22+
max_versions = 10 # keep last 10 versions
23+
cas_required = true # enforce optimistic concurrency control (server will require current secret version on the cas attribute to allow update)
24+
deactivate_version_after = "0s" # keep versions active indefinitely (example)
25+
custom_metadata = {
26+
environment = "prod"
27+
owner = "payments-team"
28+
}
29+
}
30+
31+
# Initial version (will create version 1)
32+
version = {
33+
data = jsonencode({
34+
api_key = var.api_key
35+
api_secret = var.api_secret
36+
})
37+
}
38+
}
39+
40+
# Reading a field from the secret version data
41+
locals {
42+
secret_json = jsondecode(ovh_okms_secret.example.version.data)
43+
}
44+
45+
output "api_key" {
46+
value = local.secret_json.api_key
47+
sensitive = true
48+
}
49+
```
50+
51+
Updating the secret (new version) while enforcing optimistic concurrency control using CAS:
52+
53+
```terraform
54+
resource "ovh_okms_secret" "example" {
55+
okms_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
56+
path = "app/api_credentials"
57+
58+
# Ensure no concurrent update happened: set cas to the current version
59+
# (metadata.current_version is populated after first apply)
60+
cas = ovh_okms_secret.example.metadata.current_version
61+
62+
metadata = {
63+
cas_required = true
64+
}
65+
66+
version = {
67+
data = jsonencode({
68+
api_key = var.api_key
69+
api_secret = var.new_api_secret # changed value -> creates new version
70+
})
71+
}
72+
}
73+
```
74+
75+
## Argument Reference
76+
77+
The following arguments are supported:
78+
79+
### Required
80+
81+
- `okms_id` (String) ID of the OKMS service to create the secret in.
82+
- `path` (String) Secret path (acts as the secret identifier within the OKMS instance). Immutable after creation.
83+
- `version` (Block) Definition of the version to create/update. See Version Block below. (On updates providing a new `version.data` creates a new version.)
84+
85+
### Optional
86+
87+
- `cas` (Number) Check‑and‑set parameter used only on update. Must equal the current secret version (`metadata.current_version`) for the update to succeed. Ignored on create.
88+
- `metadata` (Block) Secret metadata configuration (subset of fields are user-settable). See Metadata Block below.
89+
90+
### Metadata Block
91+
92+
User configurable attributes inside `metadata`:
93+
94+
- `cas_required` (Boolean) If true, the server will enforce optimistic concurrency control by requiring the `cas` parameter to match the current version number on every write (update) request.
95+
- `custom_metadata` (Map of String) Arbitrary key/value metadata.
96+
- `deactivate_version_after` (String) Duration (e.g. `"24h"`) after which a version is deactivated. `"0s"` (default) means never automatically deactivate.
97+
- `max_versions` (Number) Number of versions to retain (default 10). Older versions beyond this limit are pruned.
98+
99+
Computed (read‑only) metadata attributes:
100+
101+
- `created_at` (String) Creation timestamp of the secret.
102+
- `updated_at` (String) Last update timestamp.
103+
- `current_version` (Number) Current (latest) version number.
104+
- `oldest_version` (Number) Oldest retained version number.
105+
106+
### Version Block
107+
108+
Required attribute:
109+
110+
- `data` (String, Sensitive) Secret payload. Commonly set with `jsonencode(...)` so that Terraform comparisons are stable. Any valid JSON (object, array, string, number, bool) is accepted. Changing `data` creates a new secret version.
111+
112+
Computed (read‑only) attributes:
113+
114+
- `id` (Number) Version number.
115+
- `created_at` (String) Version creation timestamp.
116+
- `deactivated_at` (String) Deactivation timestamp if the version was deactivated.
117+
- `state` (String) Version state (e.g. `ACTIVE`).
118+
119+
## Attributes Reference (Read-Only)
120+
121+
In addition to arguments above, the following attributes are exported:
122+
123+
- `iam` (Block) IAM metadata: `display_name`, `id`, `tags`, `urn`.
124+
- `metadata.*` computed fields as listed above.
125+
- `version.*` computed fields as listed above.
126+
127+
## Behavior & Notes
128+
129+
- Updating with a new `version.data` performs an API PUT that creates a new version; the previous version remains (subject to `max_versions`).
130+
- If `cas_required` is true, all write operations must include a correct `cas` query parameter (the expected current version number). Set `cas = ovh_okms_secret.example.metadata.current_version` to enforce optimistic concurrency. A mismatch causes the API to reject the update (preventing overwriting unseen changes).
131+
- `cas` is ignored on create (no existing version).
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
data "ovh_okms_secret" "latest_with_data" {
2+
okms_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
3+
path = "app/api_credentials"
4+
include_data = true
5+
}
6+
7+
locals {
8+
secret_obj = jsondecode(data.ovh_okms_secret.latest_with_data.data)
9+
}
10+
11+
output "api_key" {
12+
value = local.secret_obj.api_key
13+
sensitive = true
14+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
resource "ovh_okms_secret" "example" {
2+
okms_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
3+
path = "app/api_credentials"
4+
5+
metadata = {
6+
max_versions = 10 # keep last 10 versions
7+
cas_required = true # enforce optimistic concurrency control (server will require current secret version on the cas attribute to allow update)
8+
deactivate_version_after = "0s" # keep versions active indefinitely (example)
9+
custom_metadata = {
10+
environment = "prod"
11+
appname = "helloworld"
12+
}
13+
}
14+
15+
# Initial version (will create version 1)
16+
version = {
17+
data = jsonencode({
18+
api_key = "mykey"
19+
api_secret = "mysecret"
20+
})
21+
}
22+
}
23+
24+
# Reading a field from the secret version data
25+
locals {
26+
secret_json = jsondecode(ovh_okms_secret.example.version.data)
27+
}
28+
29+
output "api_key" {
30+
value = local.secret_json.api_key
31+
sensitive = true
32+
}

0 commit comments

Comments
 (0)