Skip to content

Commit ceac56b

Browse files
committed
fix: handle obfusctated secrets in meshPlatform Azure Type
CU-86c63jkw8
1 parent d8759c9 commit ceac56b

File tree

3 files changed

+142
-11
lines changed

3 files changed

+142
-11
lines changed

docs/resources/platform.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ Optional:
237237

238238
Optional:
239239

240-
- `access_token` (String) The Access Token of the service account for replicator access.
240+
- `access_token` (String, Sensitive) The Access Token of the service account for replicator access.
241241
- `administrative_unit_id` (String) If you enter an administrative unit ID the replicated (and potentially existing) groups will be put into this AU. This can be used to limit the permission scopes which are required for the replicator principal. If you remove the AU ID again or change it, the groups will not be removed from the old AU.
242242
- `aks_cluster_name` (String) Name of the AKS cluster.
243243
- `aks_resource_group` (String) Resource group for the AKS cluster

internal/provider/platform_resource.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,6 @@ func openShiftPlatformSchema() schema.Attribute {
350350
}
351351
}
352352

353-
// TODO review done until here
354-
355353
func aksReplicationConfigSchema() schema.Attribute {
356354
return schema.SingleNestedAttribute{
357355
MarkdownDescription: "Replication configuration for AKS (optional, but required for replication)",
@@ -360,6 +358,7 @@ func aksReplicationConfigSchema() schema.Attribute {
360358
"access_token": schema.StringAttribute{
361359
MarkdownDescription: "The Access Token of the service account for replicator access.",
362360
Optional: true,
361+
Sensitive: true,
363362
},
364363
"namespace_name_pattern": schema.StringAttribute{
365364
MarkdownDescription: "Pattern for naming namespaces in AKS",
@@ -812,8 +811,6 @@ func azureReplicationConfigSchema() schema.Attribute {
812811
}
813812
}
814813

815-
// TODO continue here.
816-
817814
func azureRgReplicationConfigSchema() schema.Attribute {
818815
return schema.SingleNestedAttribute{
819816
MarkdownDescription: "Azure Resource Group-specific replication configuration for the platform.",
@@ -1053,8 +1050,6 @@ func kubernetesReplicationConfigSchema() schema.Attribute {
10531050
}
10541051
}
10551052

1056-
// TODO continue here.
1057-
10581053
func openShiftReplicationConfigSchema() schema.Attribute {
10591054
return schema.SingleNestedAttribute{
10601055
MarkdownDescription: "Replication configuration for OpenShift (optional, but required for replication)",
@@ -1155,6 +1150,8 @@ func (r *platformResource) Create(ctx context.Context, req resource.CreateReques
11551150
return
11561151
}
11571152

1153+
handleObfuscatedSecrets(&createdPlatform.Spec.Config, &platform.Spec.Config, resp.Diagnostics)
1154+
11581155
resp.Diagnostics.Append(resp.State.Set(ctx, createdPlatform)...)
11591156
}
11601157

@@ -1163,7 +1160,7 @@ func (r *platformResource) Read(ctx context.Context, req resource.ReadRequest, r
11631160
var uuid string
11641161
resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("metadata").AtName("uuid"), &uuid)...)
11651162

1166-
platform, err := r.client.ReadPlatform(uuid)
1163+
readPlatform, err := r.client.ReadPlatform(uuid)
11671164
if err != nil {
11681165
resp.Diagnostics.AddError(
11691166
fmt.Sprintf("Could not read platform with UUID '%s'", uuid),
@@ -1172,14 +1169,21 @@ func (r *platformResource) Read(ctx context.Context, req resource.ReadRequest, r
11721169
return
11731170
}
11741171

1175-
if platform == nil {
1172+
if readPlatform == nil {
11761173
// The platform was deleted outside of Terraform, so we remove it from the state
11771174
resp.State.RemoveResource(ctx)
11781175
return
11791176
}
11801177

1181-
// client data maps directly to the schema so we just need to set the state
1182-
resp.Diagnostics.Append(resp.State.Set(ctx, platform)...)
1178+
statePlatformSpec := client.MeshPlatformSpec{}
1179+
req.State.GetAttribute(ctx, path.Root("spec"), &statePlatformSpec)
1180+
if resp.Diagnostics.HasError() {
1181+
return
1182+
}
1183+
1184+
handleObfuscatedSecrets(&readPlatform.Spec.Config, &statePlatformSpec.Config, resp.Diagnostics)
1185+
1186+
resp.Diagnostics.Append(resp.State.Set(ctx, readPlatform)...)
11831187
}
11841188

11851189
func (r *platformResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
@@ -1220,6 +1224,8 @@ func (r *platformResource) Update(ctx context.Context, req resource.UpdateReques
12201224
return
12211225
}
12221226

1227+
handleObfuscatedSecrets(&updatedPlatform.Spec.Config, &platform.Spec.Config, resp.Diagnostics)
1228+
12231229
resp.Diagnostics.Append(resp.State.Set(ctx, updatedPlatform)...)
12241230
}
12251231

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package provider
2+
3+
import (
4+
"github.com/hashicorp/terraform-plugin-framework/diag"
5+
"github.com/meshcloud/terraform-provider-meshstack/client"
6+
)
7+
8+
const (
9+
obfuscatedValue = "mesh/hidden-secret"
10+
)
11+
12+
// This function is necessary to handle obfuscated secrets for meshPlatforms.
13+
// The meshPlatform API won't return secrets in plain text, but obfuscated values.
14+
// As a result we keep those from the plan/state and re-apply them to the object read from the API.
15+
//
16+
// MUST NOT PASS ANY NIL VALUES
17+
// MUST PASS compatible types
18+
func handleObfuscatedSecrets(obfuscated *client.PlatformConfig, plain *client.PlatformConfig, d diag.Diagnostics) {
19+
if obfuscated == nil || plain == nil || obfuscated.Type != plain.Type {
20+
d.AddError(
21+
"Internal Error",
22+
"Could not handle obfuscated secrets due to invalid input parameters.",
23+
)
24+
return
25+
}
26+
27+
switch obfuscated.Type {
28+
29+
case "aks":
30+
if obfuscated.Aks != nil && obfuscated.Aks.Replication != nil && plain.Aks != nil && plain.Aks.Replication != nil {
31+
// access token
32+
if obfuscated.Aks.Replication.AccessToken != nil &&
33+
plain.Aks.Replication.AccessToken != nil &&
34+
*obfuscated.Aks.Replication.AccessToken == obfuscatedValue {
35+
obfuscated.Aks.Replication.AccessToken = plain.Aks.Replication.AccessToken
36+
}
37+
// SP client secret
38+
if obfuscated.Aks.Replication.ServicePrincipal != nil &&
39+
plain.Aks.Replication.ServicePrincipal != nil &&
40+
*obfuscated.Aks.Replication.ServicePrincipal.CredentialsAuthClientSecret == obfuscatedValue {
41+
obfuscated.Aks.Replication.ServicePrincipal.CredentialsAuthClientSecret = plain.Aks.Replication.ServicePrincipal.CredentialsAuthClientSecret
42+
}
43+
}
44+
45+
case "aws":
46+
if obfuscated.Aws != nil && obfuscated.Aws.Replication != nil && plain.Aws != nil && plain.Aws.Replication != nil {
47+
// replication access-config service-user secret key
48+
if obfuscated.Aws.Replication.AccessConfig != nil &&
49+
plain.Aws.Replication.AccessConfig != nil &&
50+
obfuscated.Aws.Replication.AccessConfig.ServiceUserConfig != nil &&
51+
plain.Aws.Replication.AccessConfig.ServiceUserConfig != nil &&
52+
*obfuscated.Aws.Replication.AccessConfig.ServiceUserConfig.SecretKey == obfuscatedValue {
53+
obfuscated.Aws.Replication.AccessConfig.ServiceUserConfig.SecretKey = plain.Aws.Replication.AccessConfig.ServiceUserConfig.SecretKey
54+
}
55+
// replication AWS SSO token
56+
if obfuscated.Aws.Replication.AwsSso != nil &&
57+
plain.Aws.Replication.AwsSso != nil &&
58+
*obfuscated.Aws.Replication.AwsSso.SsoAccessToken == obfuscatedValue {
59+
obfuscated.Aws.Replication.AwsSso.SsoAccessToken = plain.Aws.Replication.AwsSso.SsoAccessToken
60+
}
61+
}
62+
63+
case "azure":
64+
if obfuscated.Azure != nil && obfuscated.Azure.Replication != nil && plain.Azure != nil && plain.Azure.Replication != nil {
65+
// replication SP client secret
66+
if obfuscated.Azure.Replication.ServicePrincipal != nil &&
67+
plain.Azure.Replication.ServicePrincipal != nil &&
68+
*obfuscated.Azure.Replication.ServicePrincipal.CredentialsAuthClientSecret == obfuscatedValue {
69+
obfuscated.Azure.Replication.ServicePrincipal.CredentialsAuthClientSecret = plain.Azure.Replication.ServicePrincipal.CredentialsAuthClientSecret
70+
}
71+
// replication provisioning customer agreement SP client secret
72+
if obfuscated.Azure.Replication.Provisioning.CustomerAgreement != nil &&
73+
plain.Azure.Replication.Provisioning.CustomerAgreement != nil {
74+
if obfuscated.Azure.Replication.Provisioning.CustomerAgreement.SourceServicePrincipal != nil &&
75+
plain.Azure.Replication.Provisioning.CustomerAgreement.SourceServicePrincipal != nil &&
76+
*obfuscated.Azure.Replication.Provisioning.CustomerAgreement.SourceServicePrincipal.CredentialsAuthClientSecret == obfuscatedValue {
77+
obfuscated.Azure.Replication.Provisioning.CustomerAgreement.SourceServicePrincipal.CredentialsAuthClientSecret = plain.Azure.Replication.Provisioning.CustomerAgreement.SourceServicePrincipal.CredentialsAuthClientSecret
78+
}
79+
}
80+
}
81+
82+
case "azurerg":
83+
if obfuscated.AzureRg != nil && obfuscated.AzureRg.Replication != nil && plain.AzureRg != nil && plain.AzureRg.Replication != nil {
84+
// replication SP client secret
85+
if obfuscated.AzureRg.Replication.ServicePrincipal != nil &&
86+
plain.AzureRg.Replication.ServicePrincipal != nil &&
87+
*obfuscated.AzureRg.Replication.ServicePrincipal.CredentialsAuthClientSecret == obfuscatedValue {
88+
obfuscated.AzureRg.Replication.ServicePrincipal.CredentialsAuthClientSecret = plain.AzureRg.Replication.ServicePrincipal.CredentialsAuthClientSecret
89+
}
90+
}
91+
92+
case "kubernetes":
93+
if obfuscated.Kubernetes != nil && obfuscated.Kubernetes.Replication != nil && plain.Kubernetes != nil && plain.Kubernetes.Replication != nil {
94+
// access token
95+
if obfuscated.Kubernetes.Replication.ClientConfig != nil &&
96+
plain.Kubernetes.Replication.ClientConfig != nil &&
97+
*obfuscated.Kubernetes.Replication.ClientConfig.AccessToken == obfuscatedValue {
98+
obfuscated.Kubernetes.Replication.ClientConfig.AccessToken = plain.Kubernetes.Replication.ClientConfig.AccessToken
99+
}
100+
}
101+
102+
case "gcp":
103+
if obfuscated.Gcp != nil && obfuscated.Gcp.Replication != nil && plain.Gcp != nil && plain.Gcp.Replication != nil {
104+
// service account credentials
105+
if obfuscated.Gcp.Replication.ServiceAccountConfig != nil &&
106+
plain.Gcp.Replication.ServiceAccountConfig != nil &&
107+
obfuscated.Gcp.Replication.ServiceAccountConfig.ServiceAccountCredentialsConfig != nil &&
108+
plain.Gcp.Replication.ServiceAccountConfig.ServiceAccountCredentialsConfig != nil &&
109+
*obfuscated.Gcp.Replication.ServiceAccountConfig.ServiceAccountCredentialsConfig.ServiceAccountCredentialsB64 == obfuscatedValue {
110+
obfuscated.Gcp.Replication.ServiceAccountConfig.ServiceAccountCredentialsConfig = plain.Gcp.Replication.ServiceAccountConfig.ServiceAccountCredentialsConfig
111+
}
112+
}
113+
114+
case "openshift":
115+
if obfuscated.OpenShift != nil && obfuscated.OpenShift.Replication != nil && plain.OpenShift != nil && plain.OpenShift.Replication != nil {
116+
// access token
117+
if obfuscated.OpenShift.Replication.ClientConfig != nil &&
118+
plain.OpenShift.Replication.ClientConfig != nil &&
119+
*obfuscated.OpenShift.Replication.ClientConfig.AccessToken == obfuscatedValue {
120+
obfuscated.OpenShift.Replication.ClientConfig.AccessToken = plain.OpenShift.Replication.ClientConfig.AccessToken
121+
}
122+
}
123+
124+
}
125+
}

0 commit comments

Comments
 (0)