Skip to content

Commit 538ddeb

Browse files
authored
Add fineGrainedAuthorization flag (#2188)
* Add fineGrainedAuthorization flag Signed-off-by: Jon Rosario <jon.rosario@datadoghq.com> * Add test case covering fineGrainedAuthorization=true Signed-off-by: Jon Rosario <jon.rosario@datadoghq.com> * Update RBAC Signed-off-by: Jon Rosario <jon.rosario@datadoghq.com> * Use annotations instead of a CRD change for fine-grainted authz Signed-off-by: Jon Rosario <jon.rosario@datadoghq.com> * Update RBAC Signed-off-by: Jon Rosario <jon.rosario@datadoghq.com> * Use annotations instead of a CRD change for fine-grainted authz Signed-off-by: Jon Rosario <jon.rosario@datadoghq.com> * Update RBAC Signed-off-by: Jon Rosario <jon.rosario@datadoghq.com> * Remove duplicates Signed-off-by: Jon Rosario <jon.rosario@datadoghq.com> --------- Signed-off-by: Jon Rosario <jon.rosario@datadoghq.com>
1 parent f13af83 commit 538ddeb

File tree

7 files changed

+148
-9
lines changed

7 files changed

+148
-9
lines changed

config/rbac/role.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ rules:
5454
- apiGroups:
5555
- ""
5656
resources:
57+
- nodes/configz
58+
- nodes/healthz
59+
- nodes/logs
5760
- nodes/metrics
61+
- nodes/pods
5862
- nodes/proxy
5963
- nodes/spec
6064
- nodes/stats

internal/controller/datadogagent/component/agent/rbac.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import (
1515
// RBAC for Agent
1616

1717
// GetDefaultAgentClusterRolePolicyRules returns the default policy rules for the Agent cluster role
18-
func GetDefaultAgentClusterRolePolicyRules(excludeNonResourceRules bool) []rbacv1.PolicyRule {
18+
func GetDefaultAgentClusterRolePolicyRules(excludeNonResourceRules bool, useFineGrainedAuthorization bool) []rbacv1.PolicyRule {
1919
policyRule := []rbacv1.PolicyRule{
20-
getKubeletPolicyRule(),
20+
getKubeletPolicyRule(useFineGrainedAuthorization),
2121
getEndpointsPolicyRule(),
2222
getLeaderElectionPolicyRule(),
2323
component.GetEKSControlPlaneMetricsPolicyRule(),
@@ -40,16 +40,31 @@ func getMetricsEndpointPolicyRule() rbacv1.PolicyRule {
4040
}
4141
}
4242

43-
func getKubeletPolicyRule() rbacv1.PolicyRule {
44-
return rbacv1.PolicyRule{
45-
APIGroups: []string{rbac.CoreAPIGroup},
46-
Resources: []string{
43+
func getKubeletPolicyRule(useFineGrainedAuthorization bool) rbacv1.PolicyRule {
44+
var resources []string
45+
if useFineGrainedAuthorization {
46+
resources = []string{
47+
rbac.NodeMetricsResource,
48+
rbac.NodeSpecResource,
49+
rbac.NodeStats,
50+
rbac.NodePodsResource,
51+
rbac.NodeHealthzResource,
52+
rbac.NodeConfigzResource,
53+
rbac.NodeLogsResource,
54+
}
55+
} else {
56+
resources = []string{
4757
rbac.NodeMetricsResource,
4858
rbac.NodeSpecResource,
4959
rbac.NodeProxyResource,
5060
rbac.NodeStats,
51-
},
52-
Verbs: []string{rbac.GetVerb},
61+
}
62+
}
63+
64+
return rbacv1.PolicyRule{
65+
APIGroups: []string{rbac.CoreAPIGroup},
66+
Resources: resources,
67+
Verbs: []string{rbac.GetVerb},
5368
}
5469
}
5570

internal/controller/datadogagent/feature/utils/utils.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
const ProcessConfigRunInCoreAgentMinVersion = "7.60.0-0"
2020
const EnableADPAnnotation = "agent.datadoghq.com/adp-enabled"
21+
const EnableFineGrainedKubeletAuthz = "agent.datadoghq.com/fine-grained-kubelet-authorization-enabled"
2122

2223
func agentSupportsRunInCoreAgent(ddaSpec *v2alpha1.DatadogAgentSpec) bool {
2324
// Agent version must >= 7.60.0 to run feature in core agent
@@ -61,3 +62,8 @@ func hasFeatureEnableAnnotation(dda metav1.Object, annotation string) bool {
6162
func HasAgentDataPlaneAnnotation(dda metav1.Object) bool {
6263
return hasFeatureEnableAnnotation(dda, EnableADPAnnotation)
6364
}
65+
66+
// HasFineGrainedKubeletAuthz returns true if the feature is enabled via the dedicated `agent.datadoghq.com/fine-grained-kubelet-authorization-enabled` annotation
67+
func HasFineGrainedKubeletAuthz(dda metav1.Object) bool {
68+
return hasFeatureEnableAnnotation(dda, EnableFineGrainedKubeletAuthz)
69+
}

internal/controller/datadogagent/global/dependencies.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/DataDog/datadog-operator/internal/controller/datadogagent/component/clusterchecksrunner"
2323
"github.com/DataDog/datadog-operator/internal/controller/datadogagent/component/objects"
2424
"github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature"
25+
featureutils "github.com/DataDog/datadog-operator/internal/controller/datadogagent/feature/utils"
2526
"github.com/DataDog/datadog-operator/internal/controller/datadogagent/object"
2627
"github.com/DataDog/datadog-operator/pkg/constants"
2728
"github.com/DataDog/datadog-operator/pkg/controller/utils"
@@ -302,14 +303,15 @@ func nodeAgentDependencies(ddaMeta metav1.Object, ddaSpec *v2alpha1.DatadogAgent
302303
var errs []error
303304
serviceAccountName := constants.GetAgentServiceAccount(ddaMeta.GetName(), ddaSpec)
304305
rbacResourcesName := agent.GetAgentRoleName(ddaMeta)
306+
useFineGrainedAuthorization := featureutils.HasFineGrainedKubeletAuthz(ddaMeta)
305307

306308
// Service account
307309
if err := manager.RBACManager().AddServiceAccountByComponent(ddaMeta.GetNamespace(), serviceAccountName, string(v2alpha1.NodeAgentComponentName)); err != nil {
308310
errs = append(errs, err)
309311
}
310312

311313
// ClusterRole creation
312-
if err := manager.RBACManager().AddClusterPolicyRulesByComponent(ddaMeta.GetNamespace(), rbacResourcesName, serviceAccountName, agent.GetDefaultAgentClusterRolePolicyRules(disableNonResourceRules(ddaSpec)), string(v2alpha1.NodeAgentComponentName)); err != nil {
314+
if err := manager.RBACManager().AddClusterPolicyRulesByComponent(ddaMeta.GetNamespace(), rbacResourcesName, serviceAccountName, agent.GetDefaultAgentClusterRolePolicyRules(disableNonResourceRules(ddaSpec), useFineGrainedAuthorization), string(v2alpha1.NodeAgentComponentName)); err != nil {
313315
errs = append(errs, err)
314316
}
315317

internal/controller/datadogagent/global/global_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,64 @@ func TestNodeAgentComponenGlobalSettings(t *testing.T) {
704704
wantVolumes: getExpectedVolumes(),
705705
want: assertAll,
706706
},
707+
{
708+
name: "Fine grained authorization enabled",
709+
singleContainerStrategyEnabled: false,
710+
dda: testutils.NewDatadogAgentBuilder().
711+
WithCredentials("apiKey", "appKey").
712+
WithGlobalKubeletConfig(hostCAPath, agentCAPath, true, podResourcesSocketDir).
713+
WithAnnotations(map[string]string{"agent.datadoghq.com/fine-grained-kubelet-authorization-enabled": "true"}).
714+
BuildWithDefaults(),
715+
wantCoreAgentEnvVars: nil,
716+
wantEnvVars: getExpectedEnvVars([]*corev1.EnvVar{
717+
{
718+
Name: constants.DDAPIKey,
719+
ValueFrom: &corev1.EnvVarSource{
720+
SecretKeyRef: &corev1.SecretKeySelector{
721+
LocalObjectReference: corev1.LocalObjectReference{
722+
Name: "-secret",
723+
},
724+
Key: v2alpha1.DefaultAPIKeyKey,
725+
},
726+
},
727+
},
728+
{
729+
Name: constants.DDAppKey,
730+
ValueFrom: &corev1.EnvVarSource{
731+
SecretKeyRef: &corev1.SecretKeySelector{
732+
LocalObjectReference: corev1.LocalObjectReference{
733+
Name: "-secret",
734+
},
735+
Key: v2alpha1.DefaultAPPKeyKey,
736+
},
737+
},
738+
},
739+
{
740+
Name: DDClusterAgentAuthToken,
741+
ValueFrom: &corev1.EnvVarSource{
742+
SecretKeyRef: &corev1.SecretKeySelector{
743+
LocalObjectReference: corev1.LocalObjectReference{
744+
Name: "-token",
745+
},
746+
Key: common.DefaultTokenKey,
747+
},
748+
},
749+
},
750+
{
751+
Name: DDKubeletTLSVerify,
752+
Value: "true",
753+
},
754+
{
755+
Name: DDKubeletCAPath,
756+
Value: agentCAPath,
757+
},
758+
}...),
759+
wantCoreAgentVolumeMounts: getExpectedVolumeMounts(kubeletCAVolumes),
760+
wantVolumeMounts: getExpectedVolumeMounts(kubeletCAVolumes),
761+
wantVolumes: getExpectedVolumes(kubeletCAVolumes),
762+
want: assertAll,
763+
wantDependency: assertClusterRolesFineGrainedAuthz,
764+
},
707765
}
708766

709767
for _, tt := range tests {
@@ -956,6 +1014,52 @@ func assertSecretBackendSpecificPerms(t testing.TB, resourcesManager feature.Res
9561014
}
9571015
}
9581016

1017+
func assertClusterRolesFineGrainedAuthz(t testing.TB, resourcesManager feature.ResourceManagers) {
1018+
store := resourcesManager.Store()
1019+
1020+
rObj, found := store.Get(kubernetes.ClusterRolesKind, "", "-agent")
1021+
if !found {
1022+
t.Error("Should have created ClusterRole")
1023+
}
1024+
1025+
role, ok := rObj.(*rbacv1.ClusterRole)
1026+
if !ok {
1027+
t.Error("ClusterRole has wrong type")
1028+
}
1029+
1030+
required := []string{
1031+
rbac.NodeConfigzResource,
1032+
rbac.NodeHealthzResource,
1033+
rbac.NodeLogsResource,
1034+
rbac.NodePodsResource,
1035+
}
1036+
unwanted := []string{rbac.NodeProxyResource}
1037+
1038+
for _, rule := range role.Rules {
1039+
allRequired := true
1040+
for _, r := range required {
1041+
if !slices.Contains(rule.Resources, r) {
1042+
allRequired = false
1043+
break
1044+
}
1045+
}
1046+
if !allRequired {
1047+
continue
1048+
}
1049+
for _, r := range unwanted {
1050+
if slices.Contains(rule.Resources, r) {
1051+
allRequired = false
1052+
break
1053+
}
1054+
}
1055+
if allRequired {
1056+
return
1057+
}
1058+
}
1059+
1060+
t.Error("ClusterRole does not have the expected resources")
1061+
}
1062+
9591063
func Test_UseFIPSAgent(t *testing.T) {
9601064
logger := logf.Log.WithName("Test_UseFIPSAgent")
9611065

internal/controller/datadogagent_controller.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ type DatadogAgentReconciler struct {
108108
// +kubebuilder:rbac:groups="",resources=nodes/proxy,verbs=get
109109
// +kubebuilder:rbac:groups="",resources=nodes/spec,verbs=get
110110
// +kubebuilder:rbac:groups="",resources=nodes/stats,verbs=get
111+
// +kubebuilder:rbac:groups="",resources=nodes/pods,verbs=get
112+
// +kubebuilder:rbac:groups="",resources=nodes/healthz,verbs=get
113+
// +kubebuilder:rbac:groups="",resources=nodes/configz,verbs=get
114+
// +kubebuilder:rbac:groups="",resources=nodes/logs,verbs=get
111115
// +kubebuilder:rbac:groups="",resources=events,verbs=get;list;watch;create;update;patch;delete
112116
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete
113117
// +kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch;create;update;patch;delete

pkg/kubernetes/rbac/const.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ const (
6868
MutatingConfigResource = "mutatingwebhookconfigurations"
6969
NamespaceResource = "namespaces"
7070
NetworkPolicyResource = "networkpolicies"
71+
NodeConfigzResource = "nodes/configz"
72+
NodeHealthzResource = "nodes/healthz"
73+
NodeLogsResource = "nodes/logs"
7174
NodeMetricsResource = "nodes/metrics"
75+
NodePodsResource = "nodes/pods"
7276
NodeProxyResource = "nodes/proxy"
7377
NodeSpecResource = "nodes/spec"
7478
NodesResource = "nodes"

0 commit comments

Comments
 (0)