|
1 | | -# Phase Provider |
| 1 | +# Phase Provider Documentation |
2 | 2 |
|
3 | | -The Phase provider is used to interact with secrets stored in Phase. The provider needs to be configured with the proper credentials before it can be used. |
| 3 | +The Phase Terraform provider allows you to manage secrets and interact with the Phase API directly from your Terraform configurations. |
4 | 4 |
|
5 | 5 | ## Example Usage |
6 | 6 |
|
| 7 | +Here's a basic example of configuring the provider and managing a secret: |
| 8 | + |
7 | 9 | ```hcl |
8 | 10 | terraform { |
9 | 11 | required_providers { |
10 | 12 | phase = { |
11 | 13 | source = "phasehq/phase" |
12 | | - version = "0.1.1" // replace with latest version |
| 14 | + version = ">= 0.2.0" // Use the latest appropriate version |
| 15 | + } |
| 16 | + random = { |
| 17 | + source = "hashicorp/random" |
| 18 | + version = "~> 3.6" |
13 | 19 | } |
14 | 20 | } |
15 | 21 | } |
16 | 22 |
|
17 | 23 | # Configure the Phase Provider |
| 24 | +# Ensure PHASE_TOKEN environment variable is set, or provide phase_token directly. |
18 | 25 | provider "phase" { |
19 | | - phase_token = "pss_service:v1:..." # or "pss_user:v1:..." // A Phase Service Token or a Phase User Token (PAT) |
| 26 | + # host = "https://your-self-hosted-phase.com" # Optional: for self-hosted instances |
| 27 | + # skip_tls_verification = true # Optional: if using self-signed certs |
20 | 28 | } |
21 | 29 |
|
22 | | -# Retrieve all secrets for an app |
23 | | -data "phase_secrets" "all" { |
24 | | - env = "development" |
25 | | - app_id = "your-app-id" |
26 | | - path = "" |
| 30 | +# Generate a random value for a secret |
| 31 | +resource "random_password" "db_password" { |
| 32 | + length = 32 |
| 33 | + special = true |
| 34 | + override_special = "_%@" |
27 | 35 | } |
28 | 36 |
|
29 | | -# Get all secrets |
30 | | -output "all_secret_keys" { |
31 | | - value = data.phase_secrets.all.secrets |
32 | | - sensitive = true |
| 37 | +# Create or manage a secret in Phase |
| 38 | +resource "phase_secret" "database_password" { |
| 39 | + app_id = "your-app-id" # Replace with your actual App ID |
| 40 | + env = "production" # Specify the environment |
| 41 | + key = "DATABASE_PASSWORD" # The key for the secret |
| 42 | + value = random_password.db_password.result |
| 43 | + path = "/database" # Optional: specify a path (defaults to "/") |
| 44 | + tags = ["database", "credentials"] # Optional: add tags that have already been created |
| 45 | + comment = "Managed by Terraform" # Optional: add a comment |
33 | 46 | } |
34 | 47 |
|
35 | | -# Alternatively, retrieve all secrets under a specific path |
36 | | -data "phase_secrets" "path_secrets" { |
37 | | - env = "development" |
38 | | - app_id = "your-app-id" |
39 | | - path = "/backend" |
| 48 | +# Fetch secrets (example: all secrets at a specific path) |
| 49 | +data "phase_secrets" "database_secrets" { |
| 50 | + app_id = phase_secret.database_password.app_id # Use values from managed resources |
| 51 | + env = phase_secret.database_password.env |
| 52 | + path = phase_secret.database_password.path |
| 53 | + tags = ["database"] # Optional: filter by tags |
| 54 | +} |
| 55 | +
|
| 56 | +# Output a specific secret fetched by the data source |
| 57 | +output "db_password_read" { |
| 58 | + value = data.phase_secrets.database_secrets.secrets["DATABASE_PASSWORD"] |
| 59 | + sensitive = true # Always mark sensitive outputs |
40 | 60 | } |
41 | 61 |
|
42 | | -# Get a single secret from that path |
43 | | -output "backend_secret_keys" { |
44 | | - value = data.phase_secrets.path_secrets.secrets["JWT_SECRET"] |
45 | | - sensitive = true |
| 62 | +# Output attributes of the managed secret |
| 63 | +output "managed_secret_version" { |
| 64 | + value = phase_secret.database_password.version |
| 65 | +} |
| 66 | +
|
| 67 | +output "managed_secret_updated_at" { |
| 68 | + value = phase_secret.database_password.updated_at |
46 | 69 | } |
47 | 70 | ``` |
48 | 71 |
|
49 | | -## Argument Reference |
| 72 | +## Provider Configuration |
50 | 73 |
|
51 | | -The following arguments are supported in the provider configuration: |
| 74 | +The following arguments are supported in the `provider "phase"` block: |
52 | 75 |
|
53 | | -* `phase_token` - (Required) The Phase authentication token. This can be either a service token or a personal access token. It can be specified with the `PHASE_SERVICE_TOKEN` or `PHASE_PAT_TOKEN` environment variable. |
54 | | -* `host` - (Optional) The Phase API host. Defaults to `https://api.phase.dev` for Phase Cloud. This can be specified with the `PHASE_HOST` environment variable. If a custom host is provided, "/service/public" will be appended to the URL. |
| 76 | +* `phase_token` - (Optional, **Required** if env var not set) The Phase authentication token. This can be a Service Token (`pss_service:...`) or a Personal Access Token (`pss_user:...`). |
| 77 | + * **Environment Variables:** This value can be provided via `PHASE_TOKEN`, `PHASE_SERVICE_TOKEN`, or `PHASE_PAT_TOKEN` environment variables (checked in that order). Providing it in the configuration block takes precedence. |
| 78 | + * **Sensitive:** This value is sensitive. |
| 79 | +* `host` - (Optional) The base URL for the Phase API. |
| 80 | + * **Default:** `https://api.phase.dev` (for Phase Cloud). |
| 81 | + * **Environment Variable:** Can be set using `PHASE_HOST`. |
| 82 | + * **Behavior:** If a custom host is provided (not the default), the provider automatically appends `/service/public` to the URL to target the correct API endpoint (e.g., `https://your-host.com/service/public`). |
| 83 | +* `skip_tls_verification` - (Optional) Set to `true` to disable SSL/TLS certificate validation for the `host`. Useful for self-hosted instances with self-signed certificates. **Use with caution.** Defaults to `false`. |
55 | 84 |
|
56 | | -## Data Sources |
| 85 | +## Resources |
57 | 86 |
|
58 | | -### phase_secrets |
| 87 | +### `phase_secret` |
59 | 88 |
|
60 | | -Retrieve secrets from Phase. |
| 89 | +Manages a single secret within a specific application and environment in Phase. |
61 | 90 |
|
62 | | -#### Argument Reference |
| 91 | +The provider handles create, read, update, and delete operations. If a `phase_secret` resource is defined for a secret that already exists (based on `app_id`, `env`, `path`, `key`), the provider will manage the existing secret and update it if necessary, rather than failing. |
63 | 92 |
|
64 | | -The following arguments are supported: |
| 93 | +#### Argument Reference |
65 | 94 |
|
66 | | -* `env` - (Required) The environment name. |
67 | | -* `app_id` - (Required) The application ID. |
68 | | -* `path` - (Optional) The path to fetch secrets from. If not provided, fetches secrets from all paths. |
69 | | -* `key` - (Optional) A specific secret key to fetch. If provided, only this secret will be returned. |
| 95 | +* `app_id` - (Required, ForceNew) The UUID of the Phase application where the secret resides. Changing this forces a new resource to be created. |
| 96 | +* `env` - (Required, ForceNew) The name of the environment within the application (e.g., `development`, `production`). Changing this forces a new resource to be created. |
| 97 | +* `key` - (Required) The key (name) of the secret (e.g., `DATABASE_URL`, `API_KEY`). |
| 98 | +* `value` - (Required, Sensitive) The value of the secret. |
| 99 | +* `path` - (Optional) The path where the secret is stored within the environment. Defaults to `/` (root). Example: `/database/credentials`. |
| 100 | +* `comment` - (Optional) A description or comment for the secret. |
| 101 | +* `tags` - (Optional) A list of strings to tag the secret with. Tags can be used for filtering when reading secrets. |
| 102 | +* `override` - (Optional) A block to configure a **Personal Secret Override**. This requires authenticating with a User Token (PAT). **Note:** This block *configures* the override value in Phase; its *activation* must still be done via the Phase Console or CLI. |
| 103 | + * `value` - (Required, Sensitive) The value to use when this override is active for the authenticated user. |
| 104 | + * `is_active` - (Required, Boolean) Must be set to `true` to configure the override. The provider currently only supports setting active overrides via this block. Setting it to `false` may not explicitly deactivate it via the API, but removes the override configuration from the state. |
70 | 105 |
|
71 | 106 | #### Attribute Reference |
72 | 107 |
|
73 | | -The following attributes are exported: |
| 108 | +In addition to the arguments above, the following attributes are exported: |
74 | 109 |
|
75 | | -* `secrets` - A map of secret keys to their corresponding values. |
| 110 | +* `id` - The unique UUID assigned to the secret by Phase upon creation. |
| 111 | +* `version` - The current version number of the secret. Incremented on each update. |
| 112 | +* `created_at` - The timestamp (UTC RFC3339 format) when the secret was first created. |
| 113 | +* `updated_at` - The timestamp (UTC RFC3339 format) when the secret was last updated. |
76 | 114 |
|
77 | | -## Fetching Secrets |
| 115 | +## Data Sources |
78 | 116 |
|
79 | | -### Fetching All Secrets for an App |
| 117 | +### `phase_secrets` |
80 | 118 |
|
81 | | -To fetch all secrets for a given app: |
| 119 | +Fetches multiple secrets from Phase based on specified filters. |
82 | 120 |
|
83 | | -```hcl |
84 | | -data "phase_secrets" "all" { |
85 | | - env = "development" |
86 | | - app_id = "your-app-id" |
87 | | - path = "" |
88 | | -} |
| 121 | +#### Argument Reference |
89 | 122 |
|
90 | | -output "all_secret_keys" { |
91 | | - value = data.phase_secrets.all.secrets |
92 | | - sensitive = true |
93 | | -} |
94 | | -``` |
| 123 | +* `app_id` - (Required) The UUID of the Phase application. |
| 124 | +* `env` - (Required) The name of the environment. |
| 125 | +* `path` - (Optional) The path to filter secrets by. If omitted or empty, secrets from the root path (`/`) are fetched by default (behavior might depend on API specifics, explicitly use `/` for root). **Note:** The API endpoint used might primarily fetch based on `key` if provided, potentially ignoring `path`. For guaranteed path-based fetching without a specific key, ensure `key` is omitted. For fetching *all* secrets regardless of path, this might require multiple data source calls or future provider enhancements if the API requires path specification. |
| 126 | +* `key` - (Optional) The key of a *specific* secret to fetch. If provided, only the secret matching this key (within the specified `app_id` and `env`, considering `path` behavior mentioned above) will be returned. |
| 127 | +* `tags` - (Optional) A list of strings (tags) to filter secrets by. Secrets matching *any* of the provided tags will be included (OR logic). |
95 | 128 |
|
96 | | -This will fetch all secrets for the specified app and environment, and output their keys. |
| 129 | +#### Attribute Reference |
97 | 130 |
|
98 | | -### Fetching a Single Secret |
| 131 | +* `secrets` - (Computed, Sensitive) A map where keys are the secret keys (e.g., `DATABASE_URL`) and values are their corresponding secret values. If a Personal Secret Override is active for the authenticated user, the override value will be returned here. |
| 132 | +* `id` - A unique identifier constructed by the provider for this data source instance based on the input arguments (`app_id`, `env`, `path`, `key`, `tags`). |
99 | 133 |
|
100 | | -To fetch a specific secret: |
| 134 | +## Importing |
101 | 135 |
|
102 | | -```hcl |
103 | | -data "phase_secrets" "single" { |
104 | | - env = "development" |
105 | | - app_id = "your-app-id" |
106 | | -} |
| 136 | +Existing secrets managed outside of Terraform can be imported into your Terraform state. |
107 | 137 |
|
108 | | -output "database_url" { |
109 | | - value = data.phase_secrets.single.secrets["DATABASE_URL"] |
110 | | - sensitive = true |
111 | | -} |
112 | | -``` |
| 138 | +Use the `terraform import` command with the following ID format: |
113 | 139 |
|
114 | | -This will fetch only the specified secret and output its value. |
| 140 | +```bash |
| 141 | +terraform import phase_secret.<resource_name_in_tf> "{app_id}:{env}:{path}:{key}" |
| 142 | +``` |
115 | 143 |
|
116 | | -### Fetching Secrets from a Specific Path |
| 144 | +**Components:** |
117 | 145 |
|
118 | | -To fetch all secrets under a specific path: |
| 146 | +* `phase_secret.<resource_name_in_tf>`: The type and name of the resource block in your Terraform configuration (`.tf` file) that corresponds to the secret you want to import. |
| 147 | +* `{app_id}`: The UUID of the application. |
| 148 | +* `{env}`: The name of the environment. |
| 149 | +* `{path}`: The **exact** path where the secret exists in Phase, including leading and trailing slashes if applicable (e.g., `/`, `/database/`, `/folder/path/`). |
| 150 | +* `{key}`: The key of the secret. |
119 | 151 |
|
120 | | -```hcl |
121 | | -data "phase_secrets" "path_secrets" { |
122 | | - env = "development" |
123 | | - app_id = "your-app-id" |
124 | | - path = "/backend" |
125 | | -} |
| 152 | +**Example:** |
126 | 153 |
|
127 | | -output "backend_secret_keys" { |
128 | | - value = data.phase_secrets.path_secrets.secrets["JWT_SECRET"] |
129 | | - sensitive = true |
130 | | -} |
| 154 | +```bash |
| 155 | +# Assuming a resource block like: resource "phase_secret" "imported_secret" { ... } |
| 156 | +terraform import phase_secret.imported_secret "907549ca-1430-4aa0-9998-290525741005:production:/database/:DB_HOST" |
131 | 157 | ``` |
132 | 158 |
|
133 | | -This will fetch all secrets under the specified path and output their keys. |
| 159 | +After importing, run `terraform plan` to see any differences between your configuration and the imported state, and adjust your `.tf` file accordingly. |
134 | 160 |
|
135 | | -### Using Secrets |
| 161 | +## Advanced Topics |
136 | 162 |
|
137 | | -You can use the fetched secrets in your Terraform configurations like this: |
| 163 | +### Personal Secret Overrides |
138 | 164 |
|
139 | | -```hcl |
140 | | -resource "some_resource" "example" { |
141 | | - database_url = data.phase_secrets.single.secrets["DATABASE_URL"] |
142 | | - api_key = data.phase_secrets.all.secrets["API_KEY"] |
143 | | - backend_config = data.phase_secrets.path_secrets.secrets["BACKEND_CONFIG"] |
144 | | -} |
145 | | -``` |
| 165 | +Personal Secret Overrides allow individual users (authenticating with a User Token/PAT) to temporarily use a different value for a secret without affecting the globally stored value. |
| 166 | + |
| 167 | +* **Authentication:** Requires a `pss_user:...` token. Service tokens (`pss_service:...`) cannot read or manage overrides. |
| 168 | +* **Provider Interaction:** |
| 169 | + * **Reading (`data "phase_secrets"`):** If an override is *active* in Phase for the authenticated user, the data source will return the override value. |
| 170 | + * **Managing (`resource "phase_secret"`):** You can define the `override` block in a `phase_secret` resource to *configure* the override value in Phase. However, **activating** the override must still be done separately through the Phase Console or CLI. The provider essentially sets the stage for the override. |
| 171 | +* **Visibility:** Overrides are personal. Only the user who created and activated the override (and is authenticated with their PAT) will see the overridden value via the provider. |
146 | 172 |
|
147 | | -Always mark outputs containing secret values as sensitive to prevent them from being displayed in console output or logs. |
| 173 | +### Working with Tags |
148 | 174 |
|
149 | | -## Personal Secret Overrides |
| 175 | +Tags provide a way to categorize and filter secrets. |
150 | 176 |
|
151 | | -Personal Secret Overrides allow individual users to temporarily override the value of a secret for their own use, without affecting the secret's value for other users or systems. Here are some important points to note about Personal Secret Overrides: |
| 177 | +Please note: To be able to assign tags, they must be already created in the Phase Console before hand. |
152 | 178 |
|
153 | | -1. **User Token Requirement**: To use Personal Secret Overrides, you must authenticate with a Phase User Token (Personal Access Token or PAT). Service tokens do not support Personal Secret Overrides. |
| 179 | +* **Assigning Tags:** Use the `tags` argument in the `phase_secret` resource: |
| 180 | + ```hcl |
| 181 | + resource "phase_secret" "api_key" { |
| 182 | + # ... other args ... |
| 183 | + key = "THIRD_PARTY_API_KEY" |
| 184 | + path = "/integrations/" |
| 185 | + tags = ["api", "billing", "external"] |
| 186 | + } |
| 187 | + ``` |
| 188 | +* **Filtering by Tags:** Use the `tags` argument in the `phase_secrets` data source. It returns secrets matching *any* of the specified tags (OR logic). |
| 189 | + ```hcl |
| 190 | + # Fetch secrets tagged with 'database' OR 'redis' |
| 191 | + data "phase_secrets" "cache_and_db" { |
| 192 | + app_id = "your-app-id" |
| 193 | + env = "staging" |
| 194 | + tags = ["database", "redis"] |
| 195 | + } |
154 | 196 |
|
155 | | -2. **Activation**: Personal Secret Overrides must be activated through the Phase Console or the Phase CLI. They cannot be directly triggered or modified through the Terraform provider. |
| 197 | + # Fetch 'api' tagged secrets specifically from the '/backend' path |
| 198 | + data "phase_secrets" "backend_api" { |
| 199 | + app_id = "your-app-id" |
| 200 | + env = "staging" |
| 201 | + path = "/backend/" |
| 202 | + tags = ["api"] |
| 203 | + } |
156 | 204 |
|
157 | | -3. **Behavior**: When a Personal Secret Override is active for a user, the Terraform provider will automatically use the overridden value instead of the main secret value when fetching secrets. |
| 205 | + output "api_keys" { |
| 206 | + value = data.phase_secrets.backend_api.secrets |
| 207 | + sensitive = true |
| 208 | + } |
| 209 | + ``` |
158 | 210 |
|
159 | | -4. **Visibility**: Personal Secret Overrides are only visible and applicable to the user who created them. Other users and systems will continue to see and use the main secret value. |
| 211 | +### Secret Metadata |
160 | 212 |
|
161 | | -5. **Temporary Nature**: Personal Secret Overrides are intended for temporary use, such as during development or testing. They should not be relied upon for production configurations. |
| 213 | +The `phase_secret` resource exports metadata about the managed secret: |
162 | 214 |
|
163 | | -Remember that the presence and value of Personal Secret Overrides depend on the authenticated user and the state of overrides in the Phase system, not on the Terraform configuration itself. |
| 215 | +```hcl |
| 216 | +resource "phase_secret" "config" { |
| 217 | + app_id = "your-app-id" |
| 218 | + env = "production" |
| 219 | + key = "FEATURE_FLAG_X" |
| 220 | + value = "true" |
| 221 | +} |
| 222 | +
|
| 223 | +output "config_version" { |
| 224 | + description = "Current version of the feature flag secret." |
| 225 | + value = phase_secret.config.version |
| 226 | +} |
| 227 | +
|
| 228 | +output "config_last_updated" { |
| 229 | + description = "Timestamp when the feature flag was last modified." |
| 230 | + value = phase_secret.config.updated_at |
| 231 | +} |
| 232 | +``` |
0 commit comments