Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OCPBUGS-48481: annotation validation policy #379

Merged
merged 3 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: azure-load-balancer-tcp-idle-timeout-validation-annotation-binding
spec:
policyName: azure-load-balancer-tcp-idle-timeout-annotation-validation-policy
validationActions: ["Deny"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingAdmissionPolicy
metadata:
name: azure-load-balancer-tcp-idle-timeout-annotation-validation-policy
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["services"]
variables:
- name: hasIdleTimeout
expression: has(object.metadata.annotations) && 'service.beta.kubernetes.io/azure-load-balancer-tcp-idle-timeout' in object.metadata.annotations
- name: idleTimeoutValue
expression: object.metadata.?annotations['service.beta.kubernetes.io/azure-load-balancer-tcp-idle-timeout'].orValue("")
- name: hasOldIdleTimeout
expression: oldObject != null && oldObject.metadata.?annotations != null && 'service.beta.kubernetes.io/azure-load-balancer-tcp-idle-timeout' in oldObject.metadata.annotations
- name: oldIdleTimeoutValue
expression: oldObject.metadata.?annotations['service.beta.kubernetes.io/azure-load-balancer-tcp-idle-timeout'].orValue("")
- name: valueHasChanged
expression: variables.hasIdleTimeout && (!variables.hasOldIdleTimeout || variables.oldIdleTimeoutValue != variables.idleTimeoutValue)
validations:
- expression: "!variables.hasIdleTimeout || !variables.valueHasChanged || variables.idleTimeoutValue.matches('^[0-9]+$')"
message: "value for annotation 'service.beta.kubernetes.io/azure-load-balancer-tcp-idle-timeout' must be an integer"
- expression: "!variables.hasIdleTimeout || !variables.valueHasChanged || (int(variables.idleTimeoutValue) >= 4 && int(variables.idleTimeoutValue) <= 100)"
message: "value for annotation 'service.beta.kubernetes.io/azure-load-balancer-tcp-idle-timeout' must be no less than 4 and no more than 100"

2 changes: 2 additions & 0 deletions pkg/cloud/azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ var (
{ReferenceObject: &rbacv1.ClusterRoleBinding{}, EmbedFsPath: "assets/azure-cloud-controller-manager-clusterrolebinding.yaml"},
{ReferenceObject: &admissionregistrationv1.ValidatingAdmissionPolicy{}, EmbedFsPath: "assets/validating-admission-policy.yaml"},
{ReferenceObject: &admissionregistrationv1.ValidatingAdmissionPolicyBinding{}, EmbedFsPath: "assets/validating-admission-policy-binding.yaml"},
{ReferenceObject: &admissionregistrationv1.ValidatingAdmissionPolicyBinding{}, EmbedFsPath: "assets/validating-admission-service-annotation-policy-binding.yaml"},
{ReferenceObject: &admissionregistrationv1.ValidatingAdmissionPolicy{}, EmbedFsPath: "assets/validating-admission-service-annotation-policy.yaml"},
}
)

Expand Down
2 changes: 1 addition & 1 deletion pkg/cloud/azure/azure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func TestResourcesRenderingSmoke(t *testing.T) {
}

resources := assets.GetRenderedResources()
assert.Len(t, resources, 8)
assert.Len(t, resources, 10)
})
}
}
Expand Down
16 changes: 12 additions & 4 deletions pkg/cloud/cloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,27 +129,31 @@ func TestGetResources(t *testing.T) {
}, {
name: "GCP resources returned as expected",
testPlatform: platformsMap[string(configv1.GCPPlatformType)],
expectedResourceCount: 4,
expectedResourceCount: 6,
expectedResourcesKindName: []string{
"Deployment/gcp-cloud-controller-manager",
"PodDisruptionBudget/gcp-cloud-controller-manager",
"ClusterRole/gcp-cloud-controller-manager",
"ClusterRoleBinding/gcp-cloud-controller-manager:cloud-provider",
"ValidatingAdmissionPolicyBinding/network-tier-annotation-binding",
"ValidatingAdmissionPolicy/network-tier-annotation-validation-policy",
},
}, {
name: "GCP resources returned as expected with single node cluster",
testPlatform: platformsMap[string(configv1.GCPPlatformType)],
expectedResourceCount: 3,
expectedResourceCount: 5,
singleReplica: true,
expectedResourcesKindName: []string{
"Deployment/gcp-cloud-controller-manager",
"ClusterRole/gcp-cloud-controller-manager",
"ClusterRoleBinding/gcp-cloud-controller-manager:cloud-provider",
"ValidatingAdmissionPolicyBinding/network-tier-annotation-binding",
"ValidatingAdmissionPolicy/network-tier-annotation-validation-policy",
},
}, {
name: "Azure resources returned as expected",
testPlatform: platformsMap[string(configv1.AzurePlatformType)],
expectedResourceCount: 9,
expectedResourceCount: 11,
expectedResourcesKindName: []string{
"Deployment/azure-cloud-controller-manager",
"DaemonSet/azure-cloud-node-manager",
Expand All @@ -159,12 +163,14 @@ func TestGetResources(t *testing.T) {
"ClusterRoleBinding/cloud-controller-manager:azure-cloud-controller-manager",
"ValidatingAdmissionPolicy/openshift-cloud-controller-manager-cloud-provider-azure-node-admission",
"ValidatingAdmissionPolicyBinding/openshift-cloud-controller-manager-cloud-provider-azure-node-admission",
"ValidatingAdmissionPolicyBinding/azure-load-balancer-tcp-idle-timeout-validation-annotation-binding",
"ValidatingAdmissionPolicy/azure-load-balancer-tcp-idle-timeout-annotation-validation-policy",
"PodDisruptionBudget/azure-cloud-controller-manager",
},
}, {
name: "Azure resources returned as expected with single node cluster",
testPlatform: platformsMap[string(configv1.AzurePlatformType)],
expectedResourceCount: 8,
expectedResourceCount: 10,
singleReplica: true,
expectedResourcesKindName: []string{
"Deployment/azure-cloud-controller-manager",
Expand All @@ -175,6 +181,8 @@ func TestGetResources(t *testing.T) {
"ClusterRoleBinding/cloud-controller-manager:azure-cloud-controller-manager",
"ValidatingAdmissionPolicy/openshift-cloud-controller-manager-cloud-provider-azure-node-admission",
"ValidatingAdmissionPolicyBinding/openshift-cloud-controller-manager-cloud-provider-azure-node-admission",
"ValidatingAdmissionPolicyBinding/azure-load-balancer-tcp-idle-timeout-validation-annotation-binding",
"ValidatingAdmissionPolicy/azure-load-balancer-tcp-idle-timeout-annotation-validation-policy",
},
}, {
name: "Azure Stack resources returned as expected",
Expand Down
7 changes: 7 additions & 0 deletions pkg/cloud/gcp/assets/validating-admission-policy-binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: network-tier-annotation-binding
spec:
policyName: network-tier-annotation-validation-policy
validationActions: ["Deny"]
26 changes: 26 additions & 0 deletions pkg/cloud/gcp/assets/validating-admission-policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: network-tier-annotation-validation-policy
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["services"]
variables:
- name: hasNetworkTier
expression: has(object.metadata.annotations) && 'cloud.google.com/network-tier' in object.metadata.annotations
- name: networkTierValue
expression: object.metadata.?annotations['cloud.google.com/network-tier'].orValue("")
- name: hasOldNetworkTier
expression: oldObject != null && oldObject.metadata.?annotations != null && 'cloud.google.com/network-tier' in oldObject.metadata.annotations
- name: oldNetworkTierValue
expression: oldObject.metadata.?annotations['cloud.google.com/network-tier'].orValue("")
- name: valueHasChanged
expression: variables.hasNetworkTier && (!variables.hasOldNetworkTier || variables.oldNetworkTierValue != variables.networkTierValue)
validations:
- expression: |
!variables.valueHasChanged || variables.networkTierValue in ['Standard', 'Premium']
message: "The annotation 'cloud.google.com/network-tier', if specified, must be either 'Standard' or 'Premium'."
3 changes: 3 additions & 0 deletions pkg/cloud/gcp/gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/asaskevich/govalidator"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
appsv1 "k8s.io/api/apps/v1"
rbacv1 "k8s.io/api/rbac/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -22,6 +23,8 @@ var (
{ReferenceObject: &appsv1.Deployment{}, EmbedFsPath: "assets/cloud-controller-manager.yaml"},
{ReferenceObject: &rbacv1.ClusterRole{}, EmbedFsPath: "assets/gcp-cloud-controller-manager-clusterrole.yaml"},
{ReferenceObject: &rbacv1.ClusterRoleBinding{}, EmbedFsPath: "assets/gcp-cloud-controller-manager-clusterrolebinding.yaml"},
{ReferenceObject: &admissionregistrationv1.ValidatingAdmissionPolicyBinding{}, EmbedFsPath: "assets/validating-admission-policy-binding.yaml"},
{ReferenceObject: &admissionregistrationv1.ValidatingAdmissionPolicy{}, EmbedFsPath: "assets/validating-admission-policy.yaml"},
}
)

Expand Down
2 changes: 1 addition & 1 deletion pkg/cloud/gcp/gcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestResourcesRenderingSmoke(t *testing.T) {
}

resources := assets.GetRenderedResources()
assert.Len(t, resources, 3)
assert.Len(t, resources, 5)
})
}
}