Skip to content

Commit

Permalink
update rbac to support secret backend multiple providers script (#459)
Browse files Browse the repository at this point in the history
* update rbac to support secret backend multiple providers script

Co-authored-by: Ursula Chen <[email protected]>
  • Loading branch information
celenechang and urseberry authored Apr 5, 2022
1 parent c4f05b1 commit 39f3f2e
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 13 deletions.
1 change: 1 addition & 0 deletions apis/datadoghq/v1alpha1/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const (
const (
DatadogHost = "DATADOG_HOST"
DDAPIKey = "DD_API_KEY"
DDSecretBackendCommand = "DD_SECRET_BACKEND_COMMAND"
DDClusterName = "DD_CLUSTER_NAME"
DDSite = "DD_SITE"
DDddURL = "DD_DD_URL"
Expand Down
22 changes: 22 additions & 0 deletions controllers/datadogagent/clusteragent.go
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,18 @@ func buildClusterRole(dda *datadoghqv1alpha1.DatadogAgent, needClusterLevelRBAC
},
}

// If the secret backend uses the provided `/readsecret_multiple_providers.sh` script, then we need to add secrets GET permissions
if *dda.Spec.Credentials.UseSecretBackend &&
(checkSecretBackendMultipleProvidersUsed(dda.Spec.Agent.Env) || checkSecretBackendMultipleProvidersUsed(dda.Spec.Agent.Config.Env) ||
checkSecretBackendMultipleProvidersUsed(dda.Spec.Agent.Apm.Env) || checkSecretBackendMultipleProvidersUsed(dda.Spec.Agent.Process.Env) ||
checkSecretBackendMultipleProvidersUsed(dda.Spec.Agent.SystemProbe.Env) || checkSecretBackendMultipleProvidersUsed(dda.Spec.Agent.Security.Env)) {
rbacRules = append(rbacRules, rbacv1.PolicyRule{
APIGroups: []string{datadoghqv1alpha1.CoreAPIGroup},
Resources: []string{datadoghqv1alpha1.SecretsResource},
Verbs: []string{datadoghqv1alpha1.GetVerb},
})
}

if needClusterLevelRBAC {
// Cluster Agent is disabled, the Agent needs extra permissions
// to collect cluster level metrics and events
Expand Down Expand Up @@ -1198,6 +1210,16 @@ func buildClusterAgentClusterRole(dda *datadoghqv1alpha1.DatadogAgent, name, age
rbacRules = append(rbacRules, getEventCollectionPolicyRule())
}

// If the secret backend uses the provided `/readsecret_multiple_providers.sh` script, then we need to add secrets GET permissions
if *dda.Spec.Credentials.UseSecretBackend &&
checkSecretBackendMultipleProvidersUsed(dda.Spec.ClusterAgent.Config.Env) {
rbacRules = append(rbacRules, rbacv1.PolicyRule{
APIGroups: []string{datadoghqv1alpha1.CoreAPIGroup},
Resources: []string{datadoghqv1alpha1.SecretsResource},
Verbs: []string{datadoghqv1alpha1.GetVerb},
})
}

if isMetricsProviderEnabled(dda.Spec.ClusterAgent) {
rbacRules = append(rbacRules,
rbacv1.PolicyRule{
Expand Down
40 changes: 27 additions & 13 deletions controllers/datadogagent/clusteragent_metricsserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,25 +119,39 @@ func (r *Reconciler) updateIfNeededExternalMetricsReaderClusterRole(logger logr.
// buildExternalMetricsReaderClusterRole creates a ClusterRole object for access to external metrics resources
func buildExternalMetricsReaderClusterRole(dda *datadoghqv1alpha1.DatadogAgent, name, agentVersion string) *rbacv1.ClusterRole {
if isMetricsProviderEnabled(dda.Spec.ClusterAgent) {
return &rbacv1.ClusterRole{
clusterRole := &rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Labels: getDefaultLabels(dda, name, agentVersion),
Labels: getDefaultLabels(dda, NewPartOfLabelValue(dda).String(), agentVersion),
Name: name,
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{
"external.metrics.k8s.io",
},
Resources: []string{"*"},
Verbs: []string{
datadoghqv1alpha1.GetVerb,
datadoghqv1alpha1.ListVerb,
datadoghqv1alpha1.WatchVerb,
},
}

rbacRules := []rbacv1.PolicyRule{
{
APIGroups: []string{
"external.metrics.k8s.io",
},
Resources: []string{"*"},
Verbs: []string{
datadoghqv1alpha1.GetVerb,
datadoghqv1alpha1.ListVerb,
datadoghqv1alpha1.WatchVerb,
},
},
}

// If the secret backend uses the provided `/readsecret_multiple_providers.sh` script, then we need to add secrets GET permissions
if *dda.Spec.Credentials.UseSecretBackend &&
checkSecretBackendMultipleProvidersUsed(dda.Spec.ClusterAgent.Config.Env) {
rbacRules = append(rbacRules, rbacv1.PolicyRule{
APIGroups: []string{datadoghqv1alpha1.CoreAPIGroup},
Resources: []string{datadoghqv1alpha1.SecretsResource},
Verbs: []string{datadoghqv1alpha1.GetVerb},
})
}

clusterRole.Rules = rbacRules
return clusterRole
}
return nil
}
11 changes: 11 additions & 0 deletions controllers/datadogagent/common_rbac.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

const secretBackendMultipleProvidersScript = "/readsecret_multiple_providers.sh"

// roleBindingInfo contains the required information to build a Cluster Role Binding
type roleBindingInfo struct {
name string
Expand Down Expand Up @@ -308,3 +310,12 @@ func isClusterRolesBindingEqual(a, b *rbacv1.ClusterRoleBinding) bool {
// by a previous Operator version.
return apiequality.Semantic.DeepEqual(a.RoleRef, b.RoleRef) && apiequality.Semantic.DeepEqual(a.Subjects, b.Subjects) && apiequality.Semantic.DeepEqual(a.ObjectMeta.OwnerReferences, b.ObjectMeta.OwnerReferences)
}

func checkSecretBackendMultipleProvidersUsed(envVarList []corev1.EnvVar) bool {
for _, envVar := range envVarList {
if envVar.Name == datadoghqv1alpha1.DDSecretBackendCommand && envVar.Value == secretBackendMultipleProvidersScript {
return true
}
}
return false
}
72 changes: 72 additions & 0 deletions controllers/datadogagent/common_rbac_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,75 @@ func newReconcilerForRbacTests(client client.Client) *Reconciler {
recorder: recorder,
}
}

func Test_checkSecretBackendMultipleProvidersUsed(t *testing.T) {

tests := []struct {
name string
envVarList []corev1.EnvVar
want bool
}{
{
name: "Secret backend multiple providers script is found",
envVarList: []corev1.EnvVar{
{
Name: "EnvVar1",
Value: "Value1",
},
{
Name: "EnvVar2",
Value: "Value2",
},
{
Name: "DD_SECRET_BACKEND_COMMAND",
Value: "/readsecret_multiple_providers.sh",
},
},
want: true,
},
{
name: "Script does not match",
envVarList: []corev1.EnvVar{
{
Name: "EnvVar1",
Value: "Value1",
},
{
Name: "EnvVar2",
Value: "Value2",
},
{
Name: "DD_SECRET_BACKEND_COMMAND",
Value: "/readsecret.sh",
},
},
want: false,
},
{
name: "EnvVar name does not match",
envVarList: []corev1.EnvVar{
{
Name: "EnvVar1",
Value: "Value1",
},
{
Name: "EnvVar2",
Value: "Value2",
},
{
Name: "DD_SECRET_BACKEND_COMMANDD",
Value: "/readsecret_multiple_providers.sh",
},
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := checkSecretBackendMultipleProvidersUsed(tt.envVarList)
if result != tt.want {
t.Errorf("checkEnvVarMatchesValue() result is %v but want %v", result, tt.want)
}
})
}
}
19 changes: 19 additions & 0 deletions docs/secret_management.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,24 @@ spec:
mountPath: /etc/secret-volume
```

The Datadog Agent also includes a script that can be used to read secrets from files mounted from Kubernetes secrets, or directly from Kubernetes secrets. This script can be used by setting `DD_SECRET_BACKEND_COMMAND` to `/readsecret_multiple_providers.sh`. An example of how to configure the DatadogAgent spec is provided below. For more details, see [Secrets Management][2].

```yaml
apiVersion: datadoghq.com/v1alpha1
kind: DatadogAgent
metadata:
name: datadog
spec:
credentials:
apiKey: ENC[k8s_secret@default/test-secret/api_key]
appKey: ENC[k8s_secret@default/test-secret/app_key]
useSecretBackend: true
agent:
env:
- name: DD_SECRET_BACKEND_COMMAND
value: "/readsecret_multiple_providers.sh"
```

**Remarks:**

* For the "Agent" and "Cluster Agent", others options exist to configure secret backend command:
Expand All @@ -228,3 +246,4 @@ spec:
* **DD_SECRET_BACKEND_TIMEOUT**: secret backend execution timeout in second. The default value is 5 seconds.

[1]: https://docs.datadoghq.com/agent/guide/secrets-management
[2]: https://docs.datadoghq.com/agent/guide/secrets-management/?tab=linux#script-for-reading-from-multiple-secret-providers

0 comments on commit 39f3f2e

Please sign in to comment.