Skip to content

Commit a6b8f70

Browse files
authored
fix: prevent permanent diff on sensitive cluster attributes (#298)
1 parent 2bdbf5c commit a6b8f70

File tree

4 files changed

+68
-49
lines changed

4 files changed

+68
-49
lines changed

argocd/resource_argocd_cluster_test.go

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,12 @@ func TestAccArgoCDCluster(t *testing.T) {
4848
),
4949
),
5050
},
51-
// TODO: not working on CI every time
52-
// {
53-
// ResourceName: "argocd_cluster.simple",
54-
// ImportState: true,
55-
// ImportStateVerify: true,
56-
// ImportStateVerifyIgnore: []string{"config.0.bearer_token", "config.0.tls_client_config"},
57-
// },
51+
{
52+
ResourceName: "argocd_cluster.simple",
53+
ImportState: true,
54+
ImportStateVerify: true,
55+
ImportStateVerifyIgnore: []string{"config.0.bearer_token"},
56+
},
5857
{
5958
Config: testAccArgoCDClusterTLSCertificate(t, acctest.RandString(10)),
6059
Check: resource.ComposeTestCheckFunc(
@@ -104,13 +103,12 @@ func TestAccArgoCDCluster_projectScope(t *testing.T) {
104103
),
105104
),
106105
},
107-
// TODO: not working on CI every time
108-
// {
109-
// ResourceName: "argocd_cluster.project_scope",
110-
// ImportState: true,
111-
// ImportStateVerify: true,
112-
// ImportStateVerifyIgnore: []string{"config.0.bearer_token", "config.0.tls_client_config"},
113-
// },
106+
{
107+
ResourceName: "argocd_cluster.project_scope",
108+
ImportState: true,
109+
ImportStateVerify: true,
110+
ImportStateVerifyIgnore: []string{"config.0.bearer_token"},
111+
},
114112
},
115113
})
116114
}
@@ -206,7 +204,7 @@ func TestAccArgoCDCluster_metadata(t *testing.T) {
206204
ResourceName: "argocd_cluster.cluster_metadata",
207205
ImportState: true,
208206
ImportStateVerify: true,
209-
ImportStateVerifyIgnore: []string{"config", "info"},
207+
ImportStateVerifyIgnore: []string{"config.0.bearer_token", "info"},
210208
},
211209
{
212210
Config: testAccArgoCDClusterMetadata_addLabels(clusterName),
@@ -226,7 +224,7 @@ func TestAccArgoCDCluster_metadata(t *testing.T) {
226224
ResourceName: "argocd_cluster.cluster_metadata",
227225
ImportState: true,
228226
ImportStateVerify: true,
229-
ImportStateVerifyIgnore: []string{"config", "info"},
227+
ImportStateVerifyIgnore: []string{"config.0.bearer_token", "info"},
230228
},
231229
{
232230
Config: testAccArgoCDClusterMetadata_addAnnotations(clusterName),
@@ -247,7 +245,7 @@ func TestAccArgoCDCluster_metadata(t *testing.T) {
247245
ResourceName: "argocd_cluster.cluster_metadata",
248246
ImportState: true,
249247
ImportStateVerify: true,
250-
ImportStateVerifyIgnore: []string{"config", "info"},
248+
ImportStateVerifyIgnore: []string{"config.0.bearer_token", "info"},
251249
},
252250
{
253251
Config: testAccArgoCDClusterMetadata_removeLabels(clusterName),
@@ -267,7 +265,7 @@ func TestAccArgoCDCluster_metadata(t *testing.T) {
267265
ResourceName: "argocd_cluster.cluster_metadata",
268266
ImportState: true,
269267
ImportStateVerify: true,
270-
ImportStateVerifyIgnore: []string{"config", "info"},
268+
ImportStateVerifyIgnore: []string{"config.0.bearer_token", "info"},
271269
},
272270
},
273271
})

argocd/schema_cluster.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ func clusterSchema() map[string]*schema.Schema {
8888
Type: schema.TypeList,
8989
Optional: true,
9090
Description: "Arguments to pass to the command when executing it",
91+
Sensitive: true,
9192
Elem: &schema.Schema{
9293
Type: schema.TypeString,
9394
},
@@ -101,6 +102,7 @@ func clusterSchema() map[string]*schema.Schema {
101102
Type: schema.TypeMap,
102103
Optional: true,
103104
Description: "Env defines additional environment variables to expose to the process. Passed as a map of strings",
105+
Sensitive: true,
104106
Elem: &schema.Schema{
105107
Type: schema.TypeString,
106108
},

argocd/structure_cluster.go

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -177,15 +177,8 @@ func flattenClusterInfo(info application.ClusterInfo) []map[string]interface{} {
177177
func flattenClusterConfig(config application.ClusterConfig, d *schema.ResourceData) []map[string]interface{} {
178178
r := map[string]interface{}{
179179
"username": config.Username,
180-
"exec_provider_config": flattenClusterConfigExecProviderConfig(config.ExecProviderConfig),
181-
}
182-
183-
if stateClusterConfig, ok := d.GetOk("config"); ok {
184-
scc := expandClusterConfig(stateClusterConfig.([]interface{})[0])
185-
186-
r["password"] = scc.Password
187-
r["bearer_token"] = scc.BearerToken
188-
r["tls_client_config"] = flattenClusterConfigTLSClientConfig(scc)
180+
"exec_provider_config": flattenClusterConfigExecProviderConfig(config.ExecProviderConfig, d),
181+
"tls_client_config": flattenClusterConfigTLSClientConfig(config.TLSClientConfig, d),
189182
}
190183

191184
if config.AWSAuthConfig != nil {
@@ -197,37 +190,63 @@ func flattenClusterConfig(config application.ClusterConfig, d *schema.ResourceDa
197190
}
198191
}
199192

193+
// ArgoCD API does not return these fields as they may contain
194+
// sensitive data. Thus, we can't track the state of these
195+
// attributes and load them from state instead.
196+
// See https://github.com/argoproj/argo-cd/blob/8840929187f4dd7b9d9fd908ea5085a006895507/server/cluster/cluster.go#L448-L466
197+
if bt, ok := d.GetOk("config.0.bearer_token"); ok {
198+
r["bearer_token"] = bt.(string)
199+
}
200+
201+
if p, ok := d.GetOk("config.0.password"); ok {
202+
r["password"] = p.(string)
203+
}
204+
200205
return []map[string]interface{}{r}
201206
}
202207

203-
func flattenClusterConfigTLSClientConfig(stateClusterConfig application.ClusterConfig) []map[string]interface{} {
204-
return []map[string]interface{}{
205-
{
206-
"ca_data": string(stateClusterConfig.CAData),
207-
"cert_data": string(stateClusterConfig.CertData),
208-
"key_data": string(stateClusterConfig.KeyData),
209-
"insecure": stateClusterConfig.Insecure,
210-
"server_name": stateClusterConfig.ServerName,
211-
},
208+
func flattenClusterConfigTLSClientConfig(tcc application.TLSClientConfig, d *schema.ResourceData) []map[string]interface{} {
209+
c := map[string]interface{}{
210+
"ca_data": string(tcc.CAData),
211+
"cert_data": string(tcc.CertData),
212+
"insecure": tcc.Insecure,
213+
"server_name": tcc.ServerName,
212214
}
215+
216+
// ArgoCD API does not return sensitive data. Thus, we can't track
217+
// the state of this attribute and load it from state instead.
218+
// See https://github.com/argoproj/argo-cd/blob/8840929187f4dd7b9d9fd908ea5085a006895507/server/cluster/cluster.go#L448-L466
219+
if kd, ok := d.GetOk("config.0.tls_client_config.0.key_data"); ok {
220+
c["key_data"] = kd.(string)
221+
}
222+
223+
return []map[string]interface{}{c}
213224
}
214225

215-
func flattenClusterConfigExecProviderConfig(epc *application.ExecProviderConfig) (result []map[string]interface{}) {
226+
func flattenClusterConfigExecProviderConfig(epc *application.ExecProviderConfig, d *schema.ResourceData) []map[string]interface{} {
216227
if epc == nil {
217-
return
228+
return nil
218229
}
219230

220-
result = []map[string]interface{}{
221-
{
222-
"api_version": epc.APIVersion,
223-
"args": epc.Args,
224-
"command": epc.Command,
225-
"env": epc.Env,
226-
"install_hint": epc.InstallHint,
227-
},
231+
c := map[string]interface{}{
232+
"api_version": epc.APIVersion,
233+
"command": epc.Command,
234+
"install_hint": epc.InstallHint,
235+
}
236+
237+
// ArgoCD API does not return these fields as they may contain
238+
// sensitive data. Thus, we can't track the state of these
239+
// attributes and load them from state instead.
240+
// See https://github.com/argoproj/argo-cd/blob/8840929187f4dd7b9d9fd908ea5085a006895507/server/cluster/cluster.go#L454-L461
241+
if a, ok := d.GetOk("config.0.exec_provider_config.0.args"); ok {
242+
c["args"] = a.([]string)
243+
}
244+
245+
if a, ok := d.GetOk("config.0.exec_provider_config.0.env"); ok {
246+
c["env"] = a.([]string)
228247
}
229248

230-
return
249+
return []map[string]interface{}{c}
231250
}
232251

233252
func flattenClusterMetadata(annotations, labels map[string]string) []map[string]interface{} {

docs/resources/cluster.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ Optional:
166166
Optional:
167167

168168
- `api_version` (String) Preferred input version of the ExecInfo
169-
- `args` (List of String) Arguments to pass to the command when executing it
169+
- `args` (List of String, Sensitive) Arguments to pass to the command when executing it
170170
- `command` (String) Command to execute
171-
- `env` (Map of String) Env defines additional environment variables to expose to the process. Passed as a map of strings
171+
- `env` (Map of String, Sensitive) Env defines additional environment variables to expose to the process. Passed as a map of strings
172172
- `install_hint` (String) This text is shown to the user when the executable doesn't seem to be present
173173

174174

0 commit comments

Comments
 (0)