Central Services and Secured Cluster Services operator.
All following commands should be run from this directory (operator/).
- Build and run operator locally. Note that this starts the operator without deploying it as a container in the cluster.
See Advanced usage for different ways of running operator.
make install run- Create
stackroximage pull secret instackroxnamespace.
Helm charts use it by default to configure pods. If it does not exist, you'll need to specifyImagePullSecretsin custom resources.
make stackrox-image-pull-secret- Create Central Custom Resource using
the provided sampletest sample.
kubectl -n stackrox delete persistentvolumeclaims stackrox-db
# TODO: switch back to user-facing samples in `config/samples/platform_v1alpha1_*.yaml`.
kubectl apply -n stackrox -f tests/common/central-cr.yaml- Once Central services come online, create Secured Cluster using test sample.
# Get init-bundle secrets document from Central and save as secrets in the cluster
kubectl -n stackrox exec deploy/central -- \
roxctl central init-bundles generate my-test-bundle --insecure-skip-tls-verify --password letmein --output-secrets - \
| kubectl -n stackrox apply -f -
# Create Secured Cluster CR
kubectl apply -n stackrox -f tests/common/secured-cluster-cr.yaml- Check status of the custom resource.
# For Central
kubectl get -n stackrox centrals.platform.stackrox.io
kubectl get -n stackrox centrals.platform.stackrox.io stackrox-central-services --output=json
# For Secured Cluster
kubectl get -n stackrox securedclusters.platform.stackrox.io
kubectl get -n stackrox securedclusters.platform.stackrox.io stackrox-secured-cluster-services --output=json- Delete the custom resource.
# Central
kubectl delete centrals.platform.stackrox.io stackrox-central-services
# Secured Cluster
kubectl delete securedclusters.platform.stackrox.io stackrox-secured-cluster-servicesThis runs unit and integration tests using a minimum k8s control plane (just apiserver and etcd). Simply run:
$ make testThis runs end-to-end tests. Requires that your kubectl is configured to connect to a k8s cluster. Simply run:
$ make test-e2eThe end-to-end tests use kuttl which is a tool for declarative testing of Kubernetes-based systems.
We have a guide that helps understand kuttl output
and learn how to troubleshoot failing end-to-end tests.
An example can be found in config/samples/platform_v1alpha1_securedcluster.yaml.
To see help on other available Makefile targets, run
$ make helpWhile make install run can launch the operator, the operator is running outside the cluster and this approach may not be sufficient to test all aspects of it.
The recommended approach is the following.
-
Build operator image
$ make docker-build
-
Make the image available for the cluster, this depends on k8s distribution you use.
You don't need to do anything when using KIND.
For minikube it could be done like this$ docker save stackrox/stackrox-operator:$(make tag) | ssh -o StrictHostKeyChecking=no -i $(minikube ssh-key) docker@$(minikube ip) docker load
Alternatively you can also set
DOCKER_BUILD_LOAD=1in the make environment in the previous build step. This will load images into the local Docker daemon instead of leaving them just in BuildKit cache. -
Install CRDs and deploy operator resources
$ make deploy
-
Validate that the operator's pod has started successfully
$ kubectl -n stackrox-operator-system describe pods
Check logs
$ kubectl -n stackrox-operator-system logs deploy/rhacs-operator-controller-manager manager -f
-
Create CRs and have fun testing. Make sure you delete the CRs before you undeploy the operator resources. Otherwise, you'll need to clean up the operands yourself.
-
When done
$ make undeploy uninstall
Note: currently creating a bundle is only supported using the RH ACS branding (ROX-11744). You need to have the following set before running most targets mentioned in this section.
$ export ROX_PRODUCT_BRANDING=RHACS_BRANDINGAlso, as of early 2026, upstream OLM does not work on GKE out of the box due to network policy issues (Slack thread). Use an OpenShift cluster, which comes with OLM pre-installed.
# Refresh bundle metadata. Make sure to check the diff and commit it.
$ make bundle
# Make sure that the operator is built and pushed
$ make docker-build docker-push
# Build and push bundle image
$ make bundle-build docker-push-bundleNote: Bundle helpers depend on Python <=3.13. By default, the build process will use the default Python version installed on the build host. You can override the python version if needed via the optional PYTHON env var, e.g. PYTHON=python3.10 make bundle-build
Build and push everything as one-liner
$ make everythingTesting bundle with Scorecard
# Test locally-built bundle files
$ make bundle-test
# Test bundle image; the image must be pushed beforehand.
$ make bundle-test-image# 0. Get the operator-sdk program.
$ make operator-sdk
# 1. Create a namespace for testing bundle.
$ kubectl create ns bundle-test
# 2. Create image pull secrets.
# You can skip this and the next patch step when using cluster from infra.rox.systems.
# If the inner magic does not work, just provide --docker-username and --docker-password with your DockerHub creds.
$ kubectl -n bundle-test create secret docker-registry my-opm-image-pull-secrets \
--docker-server=https://quay.io/v2/ \
--docker-email=ignored@email.com \
$($(command -v docker-credential-osxkeychain || command -v docker-credential-secretservice) get <<<"quay.io" | jq -r '"--docker-username=\(.Username) --docker-password=\(.Secret)"')
# 3. Configure default service account to use these pull secrets.
$ kubectl -n bundle-test patch serviceaccount default -p '{"imagePullSecrets": [{"name": "my-opm-image-pull-secrets"}]}'
# 4. Build and push operator and bundle images.
# Use one-liner above.
# 5. Run bundle.
$ `make which-operator-sdk` run bundle \
quay.io/rhacs-eng/stackrox-operator-bundle:v$(make --quiet --no-print-directory tag) \
--pull-secret-name my-opm-image-pull-secrets \
--service-account default \
--namespace bundle-test
# 6. Add image pull secrets to operator's ServiceAccount.
# Run it while the previous command executes otherwise it will fail.
# Note that serviceaccount might not exist for a few moments.
# Rerun this command until it succeeds.
# We hope that in OpenShift world things will be different and we will not have to do this.
$ kubectl -n bundle-test patch serviceaccount rhacs-operator-controller-manager -p '{"imagePullSecrets": [{"name": "my-opm-image-pull-secrets"}]}'
# You may need to bounce operator pods after this if they can't pull images for a while.
$ kubectl -n bundle-test delete pod -l app=rhacs-operator
# 7. The above operator-sdk run bundle command should complete successfully.
# If it does not, watch pod statuses and check pod logs.
$ kubectl -n bundle-test get pods
# ... and dive deep from there into the ones that are not healthy.Once done, cleanup with
kubectl -n bundle-test delete clusterserviceversions.operators.coreos.com -l operators.coreos.com/rhacs-operator.bundle-test
kubectl -n bundle-test delete subscriptions.operators.coreos.com -l operators.coreos.com/rhacs-operator.bundle-test
kubectl -n bundle-test delete catalogsources.operators.coreos.com rhacs-operator-catalogAlso, you can tear everything down with
$ kubectl delete ns bundle-testInstructions and best practices on how to extend the StackRox CRDs is contained in the separate file EXTENDING_CRDS.md.
These instructions are for deploying a version of the operator that has been pushed to the rhacs-eng Quay organization.
See above for instructions on how to deploy an OLM bundle and index that was built locally.
Note: as of early 2026, upstream OLM does not work on GKE out of the box due to network policy issues (Slack thread). Use an OpenShift cluster, which comes with OLM pre-installed.
The kubectl-kuttl binary is required for the following make targets to work.
There is a make target to install it:
make kuttlThis make target will add the executable to your $GOPATH.
If that is not on your $PATH, then you can install kuttl from its release page.
If you are deploying on an OpenShift cluster created with StackRox Infra, you can skip this section. Necessary pull secret is already included cluster-wide.
You'll also need a Quay pull secret configured in ~/.docker/config.json.
This can be retrieved on quay.io by:
- Clicking on your profile in the top right corner
- Choosing Account Settings
- Under the Docker CLI Password section, click the Generate Encrypted Password link.
- Enter your password and click Verify
- Choose Docker Configuration
- Either save the file to
~/.docker/config.jsonor merge the quay config into your already-existingconfig.json.
If git describe --dirty shows a -dirty suffix, you'll need to clean up your repo until git considers it "clean".
Otherwise, the make targets below will add -dirty to the image tag, and it likely won't be found.
Push your changes to a GitHub PR (draft is OK) to let CI build and push images for you.
Now the latest version (based off of make tag) can be installed like so:
# TODO(ROX-11744): drop branding here once operator is available via OLM from quay.io/stackrox-io
ROX_PRODUCT_BRANDING=RHACS_BRANDING make deploy-via-olmThis installs the operator into the stackrox-operator-system namespace.
This can be overridden with a TEST_NAMESPACE argument.
The version can be overridden with a VERSION argument.
For example:
ROX_PRODUCT_BRANDING=RHACS_BRANDING make deploy-via-olm TEST_NAMESPACE=my-favorite-namespace VERSION=4.5.0-123-g12deadbeefYou can blow everything away with:
$ kubectl delete ns stackrox-operator-system
# Optionally remove CRDs
$ make uninstallThe above targets use kuttl internally, so if something goes wrong you may find
this guide useful.