Skip to content
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
143 changes: 129 additions & 14 deletions manifests/0000_30_cluster-api_09_admission-policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,29 +115,29 @@ data:
- expression: "variables.specLockedExceptAuthoritativeAPI"
message: "You may only modify spec.authoritativeAPI. Any other change inside .spec is not allowed. This is because status.authoritativeAPI is set to Cluster API."

# Guard machine.openshift.io/* and kubernetes.io/* labels
# Guard machine.openshift.io/*, kubernetes.io/* and cluster.x-k8s.io labels
- expression: >
!(
variables.newLabels.exists(k,
(k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io')) &&
(k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
(variables.oldLabels[?k].orValue(null) != variables.newLabels[k])
) ||
variables.oldLabels.exists(k,
(k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io')) &&
(k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
!(k in variables.newLabels)
)
)
message: "Cannot add, modify or delete any machine.openshift.io/* or kubernetes.io/* label. This is because status.authoritativeAPI is set to Cluster API."

# Guard machine.openshift.io/* annotations
# Guard machine.openshift.io/* and cluster(s).x-k8s.io annotations
- expression: >
!(
variables.newAnn.exists(k,
k.startsWith('machine.openshift.io') &&
(k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
(variables.oldAnn[?k].orValue(null) != variables.newAnn[k])
) ||
variables.oldAnn.exists(k,
k.startsWith('machine.openshift.io') &&
(k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
!(k in variables.newAnn)
)
)
Expand All @@ -151,6 +151,121 @@ data:
variables.newLabels[?k].orValue(null) == variables.paramLabels[k]
)
message: "Cannot modify a Cluster API controlled label except to match the Cluster API mirrored machine. This is because status.authoritativeAPI is set to Cluster API."

# Don't allow setting the 'machine-template-hash' label. It should only be set by the CAPI controllers.
- expression: "variables.newLabels[?'machine-template-hash'].orValue(null) == variables.oldLabels[?'machine-template-hash'].orValue(null)"
message: "Setting the 'machine-template-hash' label is forbidden.'"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: cluster-api-machine-vap
spec:
matchResources:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-cluster-api
paramRef:
namespace: openshift-machine-api
# We 'Allow' here as we don't want to block CAPI Machine functionality
# when no MAPI machine (param) exists. This might happen when a user
# wants to not use MAPI, or is migrating.
parameterNotFoundAction: Allow
selector: {}
policyName: cluster-api-machine-vap
validationActions: [Deny]
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: cluster-api-machine-vap
spec:
failurePolicy: Fail

paramKind:
apiVersion: machine.openshift.io/v1beta1
kind: Machine

matchConstraints:
resourceRules:
- apiGroups: ["cluster.x-k8s.io"]
apiVersions: ["v1beta1"]
operations: ["UPDATE"]
resources: ["machines"]

# Requests must satisfy every matchCondition to reach the validations
matchConditions:
- name: check-only-non-service-account-requests
expression: >-
!(request.userInfo.username in [
"system:serviceaccount:openshift-machine-api:machine-api-controllers",
"system:serviceaccount:openshift-cluster-api:cluster-capi-operator"
])
- name: check-param-match
expression: 'object.metadata.name == params.metadata.name'
- name: check-authoritativeAPI-machineapi
expression: "params.?status.?authoritativeAPI.orValue(\"\") == \"MachineAPI\""
variables:
# label maps
- name: newLabels
expression: "object.metadata.?labels.orValue({})"
- name: oldLabels
expression: "oldObject.metadata.?labels.orValue({})"
- name: paramLabels
expression: "params.metadata.?labels.orValue({})"

# annotation maps
- name: newAnn
expression: "object.metadata.?annotations.orValue({})"
- name: oldAnn
expression: "oldObject.metadata.?annotations.orValue({})"

# All validations must evaluate to TRUE
validations:
# Only spec.authoritativeAPI may change
- expression: "object.spec == oldObject.spec"
message: "Changing .spec is not allowed. This is because status.authoritativeAPI is set to Machine API."

# Guard machine.openshift.io/* and kubernetes.io/* and cluster.x-k8s.io/* labels
- expression: >
!(
variables.newLabels.exists(k,
(k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
(variables.oldLabels[?k].orValue(null) != variables.newLabels[k])
) ||
variables.oldLabels.exists(k,
(k.startsWith('machine.openshift.io') || k.startsWith('kubernetes.io') || k.contains('cluster.x-k8s.io/')) &&
!(k in variables.newLabels)
)
)
message: "Cannot add, modify or delete any machine.openshift.io/*, kubernetes.io/* or cluster.x-k8s.io/* label. This is because status.authoritativeAPI is set to Machine API."

# Guard machine.openshift.io/* and cluster.x-k8s.io/* and clusters.x-k8s.io/* annotations
- expression: >
!(
variables.newAnn.exists(k,
(k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
(variables.oldAnn[?k].orValue(null) != variables.newAnn[k])
) ||
variables.oldAnn.exists(k,
(k.startsWith('machine.openshift.io') || k.contains('cluster.x-k8s.io') || k.contains('clusters.x-k8s.io')) &&
!(k in variables.newAnn)
)
)
message: "Cannot add, modify or delete any machine.openshift.io/* or cluster.x-k8s.io or clusters.x-k8s.io annotation. This is because status.authoritativeAPI is set to Machine API."

# Param-controlled labels (labels on the MAPI machine) may change only to match the value on the MAPI Machine
- expression: >
variables.paramLabels.all(
k,
variables.newLabels[?k].orValue(null) == variables.oldLabels[?k].orValue(null) ||
variables.newLabels[?k].orValue(null) == variables.paramLabels[k]
)
message: "Cannot modify a Machine API controlled label except to match the Machine API mirrored machine. This is because status.authoritativeAPI is set to Machine API."

# Don't allow setting the 'machine-template-hash' label. It should only be set by the CAPI controllers.
- expression: "variables.newLabels[?'machine-template-hash'].orValue(null) == variables.oldLabels[?'machine-template-hash'].orValue(null)"
message: "Setting the 'machine-template-hash' label is forbidden.'"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
Expand All @@ -165,15 +280,15 @@ data:
operations: ["CREATE", "UPDATE"]
resources: ["machines", "machinesets"]
variables:
- name: machineSpec
expression: "object.kind == 'Machine' ? object.spec : object.spec.template.spec"
- name: specPath
expression: "object.kind == 'Machine' ? 'spec' : 'spec.template.spec'"
- name: machineSpec
expression: "object.kind == 'Machine' ? object.spec : object.spec.template.spec"
- name: specPath
expression: "object.kind == 'Machine' ? 'spec' : 'spec.template.spec'"
validations:
- expression: "!has(variables.machineSpec.version)"
messageExpression: "variables.specPath + '.version is a forbidden field'"
- expression: "!has(variables.machineSpec.readinessGates)"
messageExpression: "variables.specPath + '.readinessGates is a forbidden field'"
- expression: "!has(variables.machineSpec.version)"
messageExpression: "variables.specPath + '.version is a forbidden field'"
- expression: "!has(variables.machineSpec.readinessGates)"
messageExpression: "variables.specPath + '.readinessGates is a forbidden field'"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
Expand Down
9 changes: 7 additions & 2 deletions pkg/controllers/machinemigration/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"testing"

"github.com/go-logr/logr"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

Expand All @@ -44,6 +45,7 @@ var k8sClient client.Client
var testEnv *envtest.Environment
var testRESTMapper meta.RESTMapper
var ctx = context.Background()
var testLogger logr.Logger

func TestMachineMigration(t *testing.T) {
RegisterFailHandler(Fail)
Expand All @@ -54,8 +56,11 @@ func TestMachineMigration(t *testing.T) {
var _ = BeforeSuite(func() {
klog.SetOutput(GinkgoWriter)

logf.SetLogger(GinkgoLogr)
ctrl.SetLogger(GinkgoLogr)
testLogger = test.NewVerboseGinkgoLogger(0)
logf.SetLogger(testLogger)
ctrl.SetLogger(testLogger)

ctx = logf.IntoContext(ctx, testLogger)

By("bootstrapping test environment")
var err error
Expand Down
9 changes: 7 additions & 2 deletions pkg/controllers/machinesetmigration/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"testing"

"github.com/go-logr/logr"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

Expand All @@ -44,6 +45,7 @@ var k8sClient client.Client
var testEnv *envtest.Environment
var testRESTMapper meta.RESTMapper
var ctx = context.Background()
var testLogger logr.Logger

func TestMachineSetMigration(t *testing.T) {
RegisterFailHandler(Fail)
Expand All @@ -54,8 +56,11 @@ func TestMachineSetMigration(t *testing.T) {
var _ = BeforeSuite(func() {
klog.SetOutput(GinkgoWriter)

logf.SetLogger(GinkgoLogr)
ctrl.SetLogger(GinkgoLogr)
testLogger = test.NewVerboseGinkgoLogger(0)
logf.SetLogger(testLogger)
ctrl.SetLogger(testLogger)

ctx = logf.IntoContext(ctx, testLogger)

By("bootstrapping test environment")
var err error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ var _ = Describe("With a running MachineSetSync controller", func() {
}

startManager := func(mgr *manager.Manager) (context.CancelFunc, chan struct{}) {
mgrCtx, mgrCancel := context.WithCancel(context.Background())
mgrCtx, mgrCancel := context.WithCancel(ctx)
mgrDone := make(chan struct{})

go func() {
Expand Down
9 changes: 7 additions & 2 deletions pkg/controllers/machinesetsync/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"testing"
"time"

"github.com/go-logr/logr"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

Expand Down Expand Up @@ -51,6 +52,7 @@ var testEnv *envtest.Environment
var testScheme *runtime.Scheme
var testRESTMapper meta.RESTMapper
var ctx = context.Background()
var testLogger logr.Logger

func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
Expand All @@ -61,8 +63,11 @@ func TestAPIs(t *testing.T) {
var _ = BeforeSuite(func() {
klog.SetOutput(GinkgoWriter)

logf.SetLogger(GinkgoLogr)
ctrl.SetLogger(GinkgoLogr)
testLogger = test.NewVerboseGinkgoLogger(0)
logf.SetLogger(testLogger)
ctrl.SetLogger(testLogger)

ctx = logf.IntoContext(ctx, testLogger)

By("bootstrapping test environment")
var err error
Expand Down
Loading