Skip to content

Commit 8b2641b

Browse files
Add dbtcloud_auth_provider resource (#655)
* Added auth provider resource * Address pr comments
1 parent 2047f7b commit 8b2641b

12 files changed

Lines changed: 1522 additions & 0 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
kind: Changes
2+
body: Added auth provider resource
3+
time: 2026-04-06T18:21:29.016021+03:00

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
.terraform
2+
*.tfstate
3+
*.tfstate.backup
4+
*.tfvars
25
vendor/
36
terraform-provider*
47
.idea

docs/resources/auth_provider.md

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
---
2+
page_title: "dbtcloud_auth_provider Resource - dbtcloud"
3+
subcategory: ""
4+
description: |-
5+
Manages an SSO auth provider for a dbt Cloud account. Supports SAML/Okta, Azure Active Directory (single-tenant, multi-tenant), and Google Workspace.
6+
Only one auth provider may exist per account. Requires the SSO feature enabled on the account (enterprise plans only).
7+
See the documentation https://docs.getdbt.com/docs/cloud/manage-access/sso-overview for more information.
8+
---
9+
10+
# dbtcloud_auth_provider (Resource)
11+
12+
13+
Manages an SSO auth provider for a dbt Cloud account. Supports SAML/Okta, Azure Active Directory (single-tenant, multi-tenant), and Google Workspace.
14+
15+
Only one auth provider may exist per account. Requires the SSO feature enabled on the account (enterprise plans only).
16+
17+
See the [documentation](https://docs.getdbt.com/docs/cloud/manage-access/sso-overview) for more information.
18+
19+
## Example Usage
20+
21+
```terraform
22+
// SAML — write-only cert (recommended, not stored in state)
23+
//
24+
// Requires Terraform >= 1.11 for write-only attribute support.
25+
// Bump cert_wo_version to rotate the cert without recreating the resource.
26+
27+
variable "saml_cert" {
28+
type = string
29+
ephemeral = true
30+
}
31+
32+
resource "dbtcloud_auth_provider" "saml" {
33+
type = "saml"
34+
entity_id = "https://your-idp.example.com/metadata"
35+
sso_url = "https://your-idp.example.com/sso/saml"
36+
37+
cert_wo = var.saml_cert
38+
cert_wo_version = 1
39+
}
40+
41+
output "login_url" {
42+
description = "SSO login URL to share with users."
43+
value = dbtcloud_auth_provider.saml.login_url
44+
}
45+
46+
47+
// SAML — all optional fields
48+
49+
resource "dbtcloud_auth_provider" "saml_full" {
50+
type = "saml"
51+
entity_id = "https://your-idp.example.com/metadata"
52+
sso_url = "https://your-idp.example.com/sso/saml"
53+
cert = file("idp-cert.pem")
54+
55+
sign_request = true
56+
attribute_map = jsonencode({
57+
email = "nameID"
58+
first_name = "firstName"
59+
last_name = "lastName"
60+
})
61+
62+
allow_password_backdoor = false
63+
}
64+
65+
66+
// Okta (identical to SAML, different type value)
67+
68+
resource "dbtcloud_auth_provider" "okta" {
69+
type = "okta"
70+
entity_id = "http://www.okta.com/<okta_app_id>"
71+
sso_url = "https://<your-org>.okta.com/app/<app_path>/sso/saml"
72+
73+
cert_wo = var.saml_cert
74+
cert_wo_version = 1
75+
}
76+
77+
78+
// Azure AD — single tenant
79+
80+
variable "azure_client_secret" {
81+
type = string
82+
ephemeral = true
83+
}
84+
85+
resource "dbtcloud_auth_provider" "azure_single_tenant" {
86+
type = "azure_single_tenant"
87+
client_id = "00000000-0000-0000-0000-000000000000"
88+
tenant_id = "11111111-1111-1111-1111-111111111111"
89+
90+
client_secret_wo = var.azure_client_secret
91+
client_secret_wo_version = 1
92+
93+
domain = "acme.com"
94+
include_indirect_groups = true
95+
max_groups_to_retrieve = 500
96+
}
97+
98+
99+
// Azure AD — multi tenant (no tenant_id required)
100+
101+
resource "dbtcloud_auth_provider" "azure_multi_tenant" {
102+
type = "azure_multi_tenant"
103+
client_id = "00000000-0000-0000-0000-000000000000"
104+
105+
client_secret_wo = var.azure_client_secret
106+
client_secret_wo_version = 1
107+
}
108+
109+
110+
// Azure Active Directory
111+
112+
resource "dbtcloud_auth_provider" "azure_active_directory" {
113+
type = "azure_active_directory"
114+
client_id = "00000000-0000-0000-0000-000000000000"
115+
tenant_id = "11111111-1111-1111-1111-111111111111"
116+
117+
client_secret_wo = var.azure_client_secret
118+
client_secret_wo_version = 1
119+
120+
domain = "acme.com"
121+
}
122+
123+
124+
// Google Workspace
125+
126+
variable "gsuite_client_secret" {
127+
type = string
128+
ephemeral = true
129+
}
130+
131+
resource "dbtcloud_auth_provider" "gsuite" {
132+
type = "gsuite"
133+
client_id = "000000000000-xxxx.apps.googleusercontent.com"
134+
135+
client_secret_wo = var.gsuite_client_secret
136+
client_secret_wo_version = 1
137+
138+
admin_refresh_token = "<oauth-refresh-token>"
139+
domain = "acme.com"
140+
gsuite_admin_id = "admin@acme.com"
141+
}
142+
```
143+
144+
<!-- schema generated by tfplugindocs -->
145+
## Schema
146+
147+
### Required
148+
149+
- `type` (String) The SSO provider type. One of: `saml`, `okta`, `gsuite`, `azure_single_tenant`, `azure_multi_tenant`, `azure_active_directory`. Changing this value forces a new resource.
150+
151+
### Optional
152+
153+
- `admin_refresh_token` (String, Sensitive) Google Workspace admin OAuth refresh token used to fetch group memberships.
154+
- `allow_password_backdoor` (Boolean) When true (default), users can still log in with email and password as a fallback. Set to false to enforce SSO-only access.
155+
- `attribute_map` (String) JSON map of SAML attribute names to dbt Cloud user fields.
156+
- `authorization_url` (String) OAuth authorization URL for Google Workspace. May be auto-populated server-side.
157+
- `cert` (String, Sensitive) SAML X.509 certificate (PEM format). Sensitive — stored in state. Consider using `cert_wo` instead. Conflicts with `cert_wo`.
158+
- `cert_wo` (String) Write-only alternative to `cert`. Not stored in state. Use `cert_wo_version` to trigger updates. Conflicts with `cert`.
159+
- `cert_wo_version` (Number) Increment to rotate `cert_wo` without changing the value.
160+
- `client_id` (String) OAuth client ID. Required for Azure AD and Google Workspace providers. Not returned by the API after save (encrypted at rest).
161+
- `client_secret` (String, Sensitive) OAuth client secret. Required for Azure AD and Google Workspace providers. Sensitive — stored in state. Consider using `client_secret_wo` instead. Conflicts with `client_secret_wo`.
162+
- `client_secret_wo` (String) Write-only alternative to `client_secret`. Not stored in state. Use `client_secret_wo_version` to trigger updates. Conflicts with `client_secret`.
163+
- `client_secret_wo_version` (Number) Increment to rotate `client_secret_wo` without changing the value.
164+
- `domain` (String) Primary domain for the Azure AD or Google Workspace tenant.
165+
- `entity_id` (String) SAML entity ID (Issuer) from your identity provider. Required for `saml` and `okta`.
166+
- `gsuite_admin_id` (String) Google Workspace admin email used to fetch group memberships.
167+
- `include_indirect_groups` (Boolean) Whether to include transitive (indirect) group memberships from Azure AD. Defaults to true.
168+
- `max_groups_to_retrieve` (Number) Maximum number of Azure AD groups to fetch per user. Defaults to 250.
169+
- `sign_request` (Boolean) Whether to sign SAML authentication requests. Defaults to false.
170+
- `slug` (String) URL-safe identifier used in the SSO login URL. Auto-generated if omitted. Immutable on accounts where auto-slug enforcement is enabled.
171+
- `sso_url` (String) SAML Single Sign-On URL from your identity provider. Required for `saml` and `okta`.
172+
- `tenant_id` (String, Sensitive) Azure AD tenant ID. Required for `azure_single_tenant`.
173+
174+
### Read-Only
175+
176+
- `cert_expiry_date` (String) Expiry date of the SAML X.509 certificate (SAML/Okta only).
177+
- `created_at` (String)
178+
- `id` (Number) The ID of the auth provider.
179+
- `login_url` (String) The SSO login URL for the account, auto-generated from the slug.
180+
- `state` (Number) The state of the auth provider (1 = active).
181+
- `updated_at` (String)
182+
183+
## Import
184+
185+
Import is supported using the following syntax:
186+
187+
```shell
188+
# Import an existing auth provider by its numeric ID.
189+
# The ID can be found via the dbt Cloud API:
190+
# GET /api/v3/accounts/{account_id}/auth-provider/
191+
192+
terraform import dbtcloud_auth_provider.example 12345
193+
```
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Manual test — SAML auth provider (cases 1 & 2)
2+
3+
## Prerequisites
4+
5+
- dbt Cloud account on an **Enterprise plan** with SSO enabled
6+
- User API token from an **Account Admin** or **Security Admin**
7+
- A SAML 2.0 IdP app (Okta developer account recommended — free at developer.okta.com)
8+
- Terraform >= 1.11 (required for `cert_wo` write-only attribute)
9+
10+
## Setup
11+
12+
```bash
13+
cp terraform.tfvars.example terraform.tfvars
14+
# Edit terraform.tfvars with real values
15+
```
16+
17+
## Running the tests
18+
19+
Only one auth provider may exist per account. Run cases separately.
20+
21+
### Case 1 — SAML with write-only cert
22+
23+
```bash
24+
TF_VAR_run_case=1 terraform init
25+
TF_VAR_run_case=1 terraform apply
26+
27+
# Verify:
28+
# - login_url output is non-empty
29+
# - slug output is auto-generated (not empty)
30+
# - cert_expiry output is populated
31+
# - terraform.tfstate does NOT contain the cert value
32+
33+
# Re-apply should show no changes:
34+
TF_VAR_run_case=1 terraform plan # expect: No changes
35+
36+
# Rotate cert: bump saml_cert_version in tfvars, then:
37+
TF_VAR_run_case=1 terraform apply # expect: in-place update, no destroy
38+
39+
# Clean up before running case 2:
40+
TF_VAR_run_case=1 terraform destroy
41+
```
42+
43+
### Case 2 — SAML with custom slug and all optional fields
44+
45+
```bash
46+
TF_VAR_run_case=2 terraform apply
47+
48+
# Verify:
49+
# - login_url contains the custom slug (var.saml_slug)
50+
# - slug output matches var.saml_slug exactly
51+
# - cert value appears as (sensitive) in plan, not plaintext
52+
# - allow_password_backdoor=false is accepted without error
53+
# - Re-apply shows no changes
54+
55+
TF_VAR_run_case=2 terraform plan # expect: No changes
56+
TF_VAR_run_case=2 terraform destroy
57+
```
58+
59+
## Checking state
60+
61+
```bash
62+
# Confirm cert_wo is absent from state (case 1):
63+
cat terraform.tfstate | grep -i cert # should show cert_expiry_date only, no cert value
64+
65+
# Confirm cert is marked sensitive in state (case 2):
66+
cat terraform.tfstate | grep -i cert # value will be present but Terraform marks it sensitive
67+
```

0 commit comments

Comments
 (0)