Skip to content

Commit 6c1c45d

Browse files
committed
feat(okms): add datasource and resource okms_secret
1 parent 85f6824 commit 6c1c45d

File tree

14 files changed

+2499
-0
lines changed

14 files changed

+2499
-0
lines changed

README.md

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

134135
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))
135136

@@ -169,6 +170,7 @@ export OVH_DOMAIN_NS3_HOST_TEST="..."
169170
export OVH_DOMAIN_DS_RECORD_ALGORITHM_TEST="..."
170171
export OVH_DOMAIN_DS_RECORD_PUBLIC_KEY_TEST="..."
171172
export OVH_DOMAIN_DS_RECORD_TAG_TEST="..."
173+
export OVH_OKMS="..."
172174

173175
$ make testacc
174176
```

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 (if `cas_required` metadata is set to true) to enforce optimistic concurrency control: its value 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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
resource "ovh_okms_secret" "example" {
2+
okms_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
3+
path = "app/api_credentials"
4+
5+
# Check‑and‑set parameter used only on update (if `cas_required` metadata is set to true)
6+
# to enforce optimistic concurrency control: its value must equal the current secret version (`metadata.current_version`)
7+
# for the update to succeed. Ignored on create.
8+
cas = 1
9+
10+
metadata = {
11+
max_versions = 10 # keep last 10 versions
12+
cas_required = true # enforce optimistic concurrency control (server will require current secret version on the cas attribute to allow update)
13+
deactivate_version_after = "0s" # keep versions active indefinitely (example)
14+
custom_metadata = {
15+
environment = "prod"
16+
appname = "helloworld"
17+
}
18+
}
19+
20+
# Initial version (will create version 1)
21+
version = {
22+
data = jsonencode({
23+
api_key = "mykey"
24+
api_secret = "mysecret"
25+
})
26+
}
27+
}
28+
29+
# Reading a field from the secret version data
30+
locals {
31+
secret_json = jsondecode(ovh_okms_secret.example.version.data)
32+
}
33+
34+
output "api_key" {
35+
value = local.secret_json.api_key
36+
sensitive = true
37+
}

0 commit comments

Comments
 (0)