Skip to content

Commit 886b027

Browse files
jaymclaude
andcommitted
Add wif_subject to export and integration resources
When exports and integrations are configured with Workload Identity Federation, the server computes an OIDC subject that must be trusted by the customer's cloud provider. Expose it as a computed `wif_subject` attribute on mondoo_export_gcs_bucket, mondoo_export_bigquery, mondoo_integration_gcp, and mondoo_integration_aws so it is available in terraform state and can feed downstream trust-policy resources. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 446aadf commit 886b027

9 files changed

Lines changed: 124 additions & 21 deletions

docs/resources/export_bigquery.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,4 @@ Export data to Google BigQuery.
4646
### Read-Only
4747

4848
- `mrn` (String) Mondoo resource name (MRN) of the integration.
49+
- `wif_subject` (String) Computed OIDC subject used when Mondoo requests a WIF token for this integration. Configure your cloud provider's trust policy to accept this subject.

docs/resources/export_gcs_bucket.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Export data to a Google Cloud Storage bucket.
5353
### Read-Only
5454

5555
- `mrn` (String) Mondoo resource name (MRN) of the integration.
56+
- `wif_subject` (String) Computed OIDC subject used when Mondoo requests a WIF token for this integration. Configure your cloud provider's trust policy to accept this subject.
5657

5758
<a id="nestedatt--credentials"></a>
5859
### Nested Schema for `credentials`

docs/resources/integration_aws.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ resource "mondoo_integration_aws" "name" {
5757
### Read-Only
5858

5959
- `mrn` (String) Integration identifier
60+
- `wif_subject` (String) Computed OIDC subject used when Mondoo requests a WIF token for this integration. Configure your cloud provider's trust policy to accept this subject.
6061

6162
<a id="nestedatt--credentials"></a>
6263
### Nested Schema for `credentials`

docs/resources/integration_gcp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ resource "mondoo_integration_gcp" "name" {
8484
### Read-Only
8585

8686
- `mrn` (String) Integration identifier
87+
- `wif_subject` (String) Computed OIDC subject used when Mondoo requests a WIF token for this integration. Configure your cloud provider's trust policy to accept this subject.
8788

8889
<a id="nestedatt--credentials"></a>
8990
### Nested Schema for `credentials`

internal/provider/export_bigquery.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ type BigQueryExportResourceModel struct {
3636
ScopeMrn types.String `tfsdk:"scope_mrn"`
3737

3838
// integration details
39-
Mrn types.String `tfsdk:"mrn"`
40-
Name types.String `tfsdk:"name"`
41-
DatasetID types.String `tfsdk:"dataset_id"`
39+
Mrn types.String `tfsdk:"mrn"`
40+
Name types.String `tfsdk:"name"`
41+
DatasetID types.String `tfsdk:"dataset_id"`
42+
WifSubject types.String `tfsdk:"wif_subject"`
4243

4344
// credentials
4445
ServiceAccountKey types.String `tfsdk:"service_account_key"`
@@ -115,6 +116,13 @@ func (r *ExportBigQueryResource) Schema(ctx context.Context, req resource.Schema
115116
stringplanmodifier.RequiresReplace(),
116117
},
117118
},
119+
"wif_subject": schema.StringAttribute{
120+
MarkdownDescription: "Computed OIDC subject used when Mondoo requests a WIF token for this integration. Configure your cloud provider's trust policy to accept this subject.",
121+
Computed: true,
122+
PlanModifiers: []planmodifier.String{
123+
stringplanmodifier.UseStateForUnknown(),
124+
},
125+
},
118126
},
119127
}
120128
}
@@ -209,6 +217,16 @@ func (r *ExportBigQueryResource) Create(ctx context.Context, req resource.Create
209217
data.Mrn = types.StringValue(string(integration.Mrn))
210218
data.Name = types.StringValue(string(integration.Name))
211219

220+
// Fetch the full integration to populate server-computed fields (e.g. wif_subject)
221+
fetched, err := r.client.GetClientIntegration(ctx, string(integration.Mrn))
222+
if err != nil {
223+
resp.Diagnostics.AddWarning("Client Warning",
224+
fmt.Sprintf("Unable to fetch integration after create to populate computed fields. Got error: %s", err))
225+
data.WifSubject = types.StringNull()
226+
} else {
227+
data.WifSubject = types.StringValue(fetched.ConfigurationOptions.BigqueryConfigurationOptions.WifSubject)
228+
}
229+
212230
// Save data into Terraform state
213231
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
214232
}
@@ -231,6 +249,7 @@ func (r *ExportBigQueryResource) Read(ctx context.Context, req resource.ReadRequ
231249

232250
// Update the state with the latest information
233251
data.Name = types.StringValue(integration.Name)
252+
data.WifSubject = types.StringValue(integration.ConfigurationOptions.BigqueryConfigurationOptions.WifSubject)
234253
// Note: We don't update service_account_key to avoid showing sensitive data
235254

236255
// Save updated data into Terraform state
@@ -294,6 +313,7 @@ func (r *ExportBigQueryResource) ImportState(ctx context.Context, req resource.I
294313
Name: types.StringValue(integration.Name),
295314
ScopeMrn: types.StringValue(integration.ScopeMRN()),
296315
DatasetID: types.StringValue(integration.ConfigurationOptions.BigqueryConfigurationOptions.DatasetId),
316+
WifSubject: types.StringValue(integration.ConfigurationOptions.BigqueryConfigurationOptions.WifSubject),
297317
ServiceAccountKey: types.StringPointerValue(nil), // Don't expose sensitive data
298318
}
299319

internal/provider/export_gcs_bucket.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type ExportGcsBucketResourceModel struct {
4242
Name types.String `tfsdk:"name"`
4343
BucketName types.String `tfsdk:"bucket_name"`
4444
ExportFormat types.String `tfsdk:"export_format"`
45+
WifSubject types.String `tfsdk:"wif_subject"`
4546

4647
// credentials
4748
Credential gcsBucketExportCredentialModel `tfsdk:"credentials"`
@@ -123,6 +124,13 @@ func (r *ExportGcsBucketResource) Schema(ctx context.Context, req resource.Schem
123124
stringplanmodifier.RequiresReplace(),
124125
},
125126
},
127+
"wif_subject": schema.StringAttribute{
128+
MarkdownDescription: "Computed OIDC subject used when Mondoo requests a WIF token for this integration. Configure your cloud provider's trust policy to accept this subject.",
129+
Computed: true,
130+
PlanModifiers: []planmodifier.String{
131+
stringplanmodifier.UseStateForUnknown(),
132+
},
133+
},
126134
"credentials": schema.SingleNestedAttribute{
127135
MarkdownDescription: "Credentials for the Google Cloud Storage bucket.",
128136
Required: true,
@@ -235,6 +243,16 @@ func (r *ExportGcsBucketResource) Create(ctx context.Context, req resource.Creat
235243
data.Mrn = types.StringValue(string(integration.Mrn))
236244
data.Name = types.StringValue(string(integration.Name))
237245

246+
// Fetch the full integration to populate server-computed fields (e.g. wif_subject)
247+
fetched, err := r.client.GetClientIntegration(ctx, string(integration.Mrn))
248+
if err != nil {
249+
resp.Diagnostics.AddWarning("Client Warning",
250+
fmt.Sprintf("Unable to fetch integration after create to populate computed fields. Got error: %s", err))
251+
data.WifSubject = types.StringNull()
252+
} else {
253+
data.WifSubject = types.StringValue(fetched.ConfigurationOptions.GcsBucketConfigurationOptions.WifSubject)
254+
}
255+
238256
// Save data into Terraform state
239257
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
240258
}
@@ -249,7 +267,13 @@ func (r *ExportGcsBucketResource) Read(ctx context.Context, req resource.ReadReq
249267
return
250268
}
251269

252-
// Read API call logic
270+
// Refresh server-computed fields (e.g. wif_subject) from the API.
271+
integration, err := r.client.GetClientIntegration(ctx, data.Mrn.ValueString())
272+
if err != nil {
273+
resp.Diagnostics.AddError("Error reading GCS bucket export integration", err.Error())
274+
return
275+
}
276+
data.WifSubject = types.StringValue(integration.ConfigurationOptions.GcsBucketConfigurationOptions.WifSubject)
253277

254278
// Save updated data into Terraform state
255279
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
@@ -319,6 +343,7 @@ func (r *ExportGcsBucketResource) ImportState(ctx context.Context, req resource.
319343
ScopeMrn: types.StringValue(integration.ScopeMRN()),
320344
BucketName: types.StringValue(integration.ConfigurationOptions.GcsBucketConfigurationOptions.Bucket),
321345
ExportFormat: types.StringValue(integration.ConfigurationOptions.GcsBucketConfigurationOptions.Output),
346+
WifSubject: types.StringValue(integration.ConfigurationOptions.GcsBucketConfigurationOptions.WifSubject),
322347

323348
Credential: gcsBucketExportCredentialModel{
324349
PrivateKey: types.StringPointerValue(nil),

internal/provider/gql.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -839,8 +839,9 @@ type GithubConfigurationOptions struct {
839839
}
840840

841841
type GcsBucketConfigurationOptions struct {
842-
Bucket string
843-
Output string
842+
Bucket string
843+
Output string
844+
WifSubject string
844845
}
845846

846847
type AwsS3ConfigurationOptions struct {
@@ -850,7 +851,8 @@ type AwsS3ConfigurationOptions struct {
850851
}
851852

852853
type BigqueryConfigurationOptions struct {
853-
DatasetId string
854+
DatasetId string
855+
WifSubject string
854856
}
855857

856858
type GitlabConfigurationOptions struct {
@@ -875,11 +877,13 @@ type MsIntuneConfigurationOptions struct {
875877
type HostedAwsConfigurationOptions struct {
876878
AccessKeyId string
877879
Role string
880+
WifSubject string
878881
}
879882

880883
type GcpConfigurationOptions struct {
881884
ProjectId string
882885
DiscoverAll bool
886+
WifSubject string
883887
}
884888

885889
type ShodanConfigurationOptions struct {

internal/provider/integration_aws_resource.go

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ type integrationAwsResourceModel struct {
3838
SpaceID types.String `tfsdk:"space_id"`
3939

4040
// integration details
41-
Mrn types.String `tfsdk:"mrn"`
42-
Name types.String `tfsdk:"name"`
41+
Mrn types.String `tfsdk:"mrn"`
42+
Name types.String `tfsdk:"name"`
43+
WifSubject types.String `tfsdk:"wif_subject"`
4344

4445
// AWS credentials
4546
Credential integrationAwsCredentialModel `tfsdk:"credentials"`
@@ -116,6 +117,13 @@ func (r *integrationAwsResource) Schema(ctx context.Context, req resource.Schema
116117
stringvalidator.LengthAtMost(250),
117118
},
118119
},
120+
"wif_subject": schema.StringAttribute{
121+
MarkdownDescription: "Computed OIDC subject used when Mondoo requests a WIF token for this integration. Configure your cloud provider's trust policy to accept this subject.",
122+
Computed: true,
123+
PlanModifiers: []planmodifier.String{
124+
stringplanmodifier.UseStateForUnknown(),
125+
},
126+
},
119127
"credentials": schema.SingleNestedAttribute{
120128
Required: true,
121129
Attributes: map[string]schema.Attribute{
@@ -229,6 +237,16 @@ func (r *integrationAwsResource) Create(ctx context.Context, req resource.Create
229237
data.Name = types.StringValue(string(integration.Name))
230238
data.SpaceID = types.StringValue(space.ID())
231239

240+
// Fetch the full integration to populate server-computed fields (e.g. wif_subject)
241+
fetched, err := r.client.GetClientIntegration(ctx, string(integration.Mrn))
242+
if err != nil {
243+
resp.Diagnostics.AddWarning("Client Warning",
244+
fmt.Sprintf("Unable to fetch integration after create to populate computed fields. Got error: %s", err))
245+
data.WifSubject = types.StringNull()
246+
} else {
247+
data.WifSubject = types.StringValue(fetched.ConfigurationOptions.HostedAwsConfigurationOptions.WifSubject)
248+
}
249+
232250
// Save data into Terraform state
233251
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
234252
}
@@ -243,7 +261,13 @@ func (r *integrationAwsResource) Read(ctx context.Context, req resource.ReadRequ
243261
return
244262
}
245263

246-
// Read API call logic
264+
// Refresh server-computed fields (e.g. wif_subject) from the API.
265+
integration, err := r.client.GetClientIntegration(ctx, data.Mrn.ValueString())
266+
if err != nil {
267+
resp.Diagnostics.AddError("Error reading AWS integration", err.Error())
268+
return
269+
}
270+
data.WifSubject = types.StringValue(integration.ConfigurationOptions.HostedAwsConfigurationOptions.WifSubject)
247271

248272
// Save updated data into Terraform state
249273
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
@@ -310,9 +334,10 @@ func (r *integrationAwsResource) ImportState(ctx context.Context, req resource.I
310334
}
311335

312336
model := integrationAwsResourceModel{
313-
SpaceID: types.StringValue(integration.SpaceID()),
314-
Mrn: types.StringValue(integration.Mrn),
315-
Name: types.StringValue(integration.Name),
337+
SpaceID: types.StringValue(integration.SpaceID()),
338+
Mrn: types.StringValue(integration.Mrn),
339+
Name: types.StringValue(integration.Name),
340+
WifSubject: types.StringValue(integration.ConfigurationOptions.HostedAwsConfigurationOptions.WifSubject),
316341
Credential: integrationAwsCredentialModel{
317342
Role: &roleCredentialModel{
318343
RoleArn: types.StringValue(integration.ConfigurationOptions.HostedAwsConfigurationOptions.Role),

internal/provider/integration_gcp_resource.go

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ type integrationGcpResourceModel struct {
3535
SpaceID types.String `tfsdk:"space_id"`
3636

3737
// integration details
38-
Mrn types.String `tfsdk:"mrn"`
39-
Name types.String `tfsdk:"name"`
40-
ProjectId types.String `tfsdk:"project_id"`
38+
Mrn types.String `tfsdk:"mrn"`
39+
Name types.String `tfsdk:"name"`
40+
ProjectId types.String `tfsdk:"project_id"`
41+
WifSubject types.String `tfsdk:"wif_subject"`
4142

4243
// credentials
4344
Credential integrationGcpCredentialModel `tfsdk:"credentials"`
@@ -81,6 +82,13 @@ func (r *integrationGcpResource) Schema(ctx context.Context, req resource.Schema
8182
MarkdownDescription: "GCP project ID",
8283
Optional: true,
8384
},
85+
"wif_subject": schema.StringAttribute{
86+
MarkdownDescription: "Computed OIDC subject used when Mondoo requests a WIF token for this integration. Configure your cloud provider's trust policy to accept this subject.",
87+
Computed: true,
88+
PlanModifiers: []planmodifier.String{
89+
stringplanmodifier.UseStateForUnknown(),
90+
},
91+
},
8492
"credentials": schema.SingleNestedAttribute{
8593
Required: true,
8694
Attributes: map[string]schema.Attribute{
@@ -169,6 +177,16 @@ func (r *integrationGcpResource) Create(ctx context.Context, req resource.Create
169177
data.Name = types.StringValue(string(integration.Name))
170178
data.SpaceID = types.StringValue(space.ID())
171179

180+
// Fetch the full integration to populate server-computed fields (e.g. wif_subject)
181+
fetched, err := r.client.GetClientIntegration(ctx, string(integration.Mrn))
182+
if err != nil {
183+
resp.Diagnostics.AddWarning("Client Warning",
184+
fmt.Sprintf("Unable to fetch integration after create to populate computed fields. Got error: %s", err))
185+
data.WifSubject = types.StringNull()
186+
} else {
187+
data.WifSubject = types.StringValue(fetched.ConfigurationOptions.GcpConfigurationOptions.WifSubject)
188+
}
189+
172190
// Save data into Terraform state
173191
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
174192
}
@@ -183,7 +201,13 @@ func (r *integrationGcpResource) Read(ctx context.Context, req resource.ReadRequ
183201
return
184202
}
185203

186-
// Read API call logic
204+
// Refresh server-computed fields (e.g. wif_subject) from the API.
205+
integration, err := r.client.GetClientIntegration(ctx, data.Mrn.ValueString())
206+
if err != nil {
207+
resp.Diagnostics.AddError("Error reading GCP integration", err.Error())
208+
return
209+
}
210+
data.WifSubject = types.StringValue(integration.ConfigurationOptions.GcpConfigurationOptions.WifSubject)
187211

188212
// Save updated data into Terraform state
189213
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
@@ -255,10 +279,11 @@ func (r *integrationGcpResource) ImportState(ctx context.Context, req resource.I
255279
}
256280

257281
model := integrationGcpResourceModel{
258-
Mrn: types.StringValue(integration.Mrn),
259-
Name: types.StringValue(integration.Name),
260-
SpaceID: types.StringValue(integration.SpaceID()),
261-
ProjectId: types.StringValue(integration.ConfigurationOptions.GcpConfigurationOptions.ProjectId),
282+
Mrn: types.StringValue(integration.Mrn),
283+
Name: types.StringValue(integration.Name),
284+
SpaceID: types.StringValue(integration.SpaceID()),
285+
ProjectId: types.StringValue(integration.ConfigurationOptions.GcpConfigurationOptions.ProjectId),
286+
WifSubject: types.StringValue(integration.ConfigurationOptions.GcpConfigurationOptions.WifSubject),
262287
Credential: integrationGcpCredentialModel{
263288
PrivateKey: types.StringPointerValue(nil),
264289
},

0 commit comments

Comments
 (0)