Browse Source

first commit

main
Nicolas Massé 2 years ago
commit
7cdcf51b7f
  1. 11
      README.md
  2. 28
      argocd-app.yaml
  3. 5
      charts/rhacs/Chart.yaml
  4. 215
      charts/rhacs/files/stackrox-configure-hook/configure.yaml
  5. 8
      charts/rhacs/files/stackrox-configure-hook/entrypoint.sh
  6. 58
      charts/rhacs/files/stackrox-init-hook/configure-acs.sh
  7. 5
      charts/rhacs/templates/_helpers.tpl
  8. 116
      charts/rhacs/templates/acs.yaml
  9. 151
      charts/rhacs/templates/hook.yaml
  10. 37
      charts/rhacs/templates/operator.yaml
  11. 24
      charts/rhacs/templates/registry-reader.yaml
  12. 55
      charts/rhacs/templates/route.yaml
  13. 5
      charts/rhacs/values.yaml

11
README.md

@ -0,0 +1,11 @@
# Deploy Red Hat ACS, the GitOps way!
An all-in-one installation of [Red Hat ACS](https://docs.openshift.com/acs/4.3/welcome/index.html) using GitOps:
- Red Hat ACS Operator
- **Central** installation
- [Init bundle](https://docs.openshift.com/acs/4.3/installing/installing_ocp/init-bundle-ocp.html) generation
- **Secure Cluster Service** installation
- Dedicated route for the console with the default router certificate. That is to say, no more "invalid certificate" warning!
- Post-configuration hook to deploy Red Hat ACS configuration
- A link to the Central from within the OpenShift Console

28
argocd-app.yaml

@ -0,0 +1,28 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: rhacs
namespace: openshift-gitops
spec:
project: default
source:
repoURL: https://github.com/nmasse-itix/rhacs-gitops.git
targetRevision: main
path: charts/rhacs
helm:
parameters:
- name: masterKey
value: "S3cr3t!"
- name: openshiftDnsZone
value: apps.ocp.tld
destination:
server: https://kubernetes.default.svc
syncPolicy:
syncOptions:
- CreateNamespace=false
automated:
selfHeal: true
prune: true
managedNamespaceMetadata:
labels:
argocd.argoproj.io/managed-by: openshift-gitops

5
charts/rhacs/Chart.yaml

@ -0,0 +1,5 @@
apiVersion: v2
name: rhacs
type: application
version: 0.0.1
appVersion: "0.0.1"

215
charts/rhacs/files/stackrox-configure-hook/configure.yaml

@ -0,0 +1,215 @@
- name: Configure RHACS
hosts: localhost
gather_facts: no
vars:
ansible_connection: local
acs_api: https://{{ central_hostname }}/v1
validate_certs: no
tasks:
- name: Get Stackrox central's Route
kubernetes.core.k8s_info:
api_version: route.openshift.io/v1
kind: Route
name: central
namespace: stackrox
register: central_route
failed_when: central_route.resources|length == 0
until: central_route is succeeded
retries: 60
delay: 5
- set_fact:
central_hostname: '{{ central_route.resources[0].spec.host }}:443'
- name: Get Stackrox central's admin password
kubernetes.core.k8s_info:
api_version: v1
kind: Secret
name: central-admin
namespace: stackrox
register: admin_secret
failed_when: admin_secret.resources|length == 0
until: admin_secret is succeeded
retries: 60
delay: 5
- set_fact:
central_admin_password: '{{ admin_secret.resources[0].data.password | b64decode }}'
- name: Check if jmespath is available locally
debug: msg={{ dummy|json_query('@') }}
register: check_jmespath
ignore_errors: yes
vars:
dummy: Hello World
- name: Ensure JMESPath is installed
assert:
that:
- 'check_jmespath is success'
msg: >
The JMESPath library is required by this playbook.
Please install the JMESPath library with 'pip install jmespath'.
- name: Wait for the Central to be ready
uri:
url: 'https://{{ central_hostname }}'
validate_certs: '{{ validate_certs }}'
register: healthcheck
changed_when: false
until: healthcheck is succeeded
retries: 60
delay: 5
- name: Get K8s secret
kubernetes.core.k8s_info:
api_version: v1
kind: Secret
name: stackrox-cicd-token
namespace: stackrox
register: cicd_token_secret
- name: Create the CI/CD API Token
uri:
url: '{{ acs_api }}/apitokens/generate'
method: POST
status_code: "200"
validate_certs: '{{ validate_certs }}'
url_username: admin
url_password: '{{ central_admin_password }}'
body: '{{ token_creation }}'
body_format: json
force_basic_auth: yes
register: create_apitoken_response
changed_when: create_apitoken_response.status == 200
when: cicd_token_secret.resources|length == 0
vars:
token_creation:
name: tekton-pipelines
role: Continuous Integration
- set_fact:
apitoken_value: '{{ create_apitoken_response.json.token }}'
when: cicd_token_secret.resources|length == 0
- name: Create the K8s Secret
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Secret
metadata:
name: stackrox-cicd-token
namespace: stackrox
stringData:
token: '{{ apitoken_value }}'
endpoint: '{{ central_hostname }}'
when: apitoken_value is defined
- name: Get secrets in the stackrox namespace
kubernetes.core.k8s_info:
api_version: v1
kind: Secret
namespace: stackrox
register: stackrox_secrets
failed_when: stackrox_secrets.resources|length == 0
- set_fact:
registry_reader_token: '{{ stackrox_secrets.resources | json_query(query) | first | b64decode }}'
vars:
query: >
[?metadata.annotations."kubernetes.io/service-account.name" == `stackrox-registry-reader` && type == `kubernetes.io/service-account-token`].data.token
- name: Find image registry integrations
uri:
url: '{{ acs_api }}/imageintegrations'
validate_certs: '{{ validate_certs }}'
url_username: admin
url_password: '{{ central_admin_password }}'
force_basic_auth: yes
register: find_image_integrations_response
changed_when: false
- set_fact:
image_integration_id: '{{ (find_image_integrations_response.json | json_query(query) | first).id }}'
when: find_image_integrations_response.json | json_query(query) | count > 0
vars:
query: integrations[?type == `docker` && docker.endpoint == `image-registry.openshift-image-registry.svc:5000`]
- name: Create the image registry integration
uri:
url: '{{ acs_api }}/imageintegrations'
method: POST
status_code: "200"
validate_certs: '{{ validate_certs }}'
url_username: admin
url_password: '{{ central_admin_password }}'
body: '{{ integration }}'
body_format: json
force_basic_auth: yes
register: create_image_integration_response
changed_when: create_image_integration_response.status == 200
when: image_integration_id is not defined
vars:
integration:
name: OpenShift Internal Registry
autogenerated: false
categories:
- REGISTRY
clusterId: ""
docker:
endpoint: image-registry.openshift-image-registry.svc:5000
insecure: true
username: stackrox-registry-reader
password: '{{ registry_reader_token }}'
type: docker
- set_fact:
image_integration_id: '{{ create_image_integration_response.json.id }}'
when: image_integration_id is not defined
- debug:
var: image_integration_id
- name: Find auth providers
uri:
url: '{{ acs_api }}/authProviders'
validate_certs: '{{ validate_certs }}'
url_username: admin
url_password: '{{ central_admin_password }}'
force_basic_auth: yes
register: find_auth_providers_response
changed_when: false
- set_fact:
auth_provider_id: '{{ (find_auth_providers_response.json | json_query(query) | first).id }}'
when: find_auth_providers_response.json | json_query(query) | count > 0
vars:
query: authProviders[?name == `OpenShift`]
- name: Create the OpenShift auth provider
uri:
url: '{{ acs_api }}/authProviders'
method: POST
status_code: "200"
validate_certs: '{{ validate_certs }}'
url_username: admin
url_password: '{{ central_admin_password }}'
body: '{{ auth }}'
body_format: json
force_basic_auth: yes
register: create_auth_provider_response
changed_when: create_auth_provider_response.status == 200
when: auth_provider_id is not defined
vars:
auth:
name: OpenShift
type: openshift
validated: true
- set_fact:
auth_provider_id: '{{ create_auth_provider_response.json.id }}'
when: auth_provider_id is not defined
- debug:
var: auth_provider_id

8
charts/rhacs/files/stackrox-configure-hook/entrypoint.sh

@ -0,0 +1,8 @@
#!/bin/bash
set -Eeuo pipefail
ansible-galaxy collection install community.general
ansible-playbook configure.yaml
exit 0

58
charts/rhacs/files/stackrox-init-hook/configure-acs.sh

@ -0,0 +1,58 @@
#!/bin/bash
set -Eeuo pipefail
mkdir -p /tmp/bin
curl -sfLo /tmp/bin/roxctl https://mirror.openshift.com/pub/rhacs/assets/4.0.0/bin/Linux/roxctl
chmod 755 /tmp/bin/roxctl
curl -sLo /tmp/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
chmod 755 /tmp/bin/jq
export PATH="/tmp/bin:$PATH"
echo "========================================================================"
echo " Connecting to Red Hat ACS"
echo "========================================================================"
echo
export ROX_CENTRAL_ADDRESS="$(oc get route central -n stackrox -o go-template='{{.spec.host}}'):443"
while ! curl -sfko /dev/null "https://$ROX_CENTRAL_ADDRESS/"; do
echo "Red Hat ACS not ready..."
sleep 5
# There is a risk the central's route to be created after this script started
# so we need to periodically refresh it
export ROX_CENTRAL_ADDRESS="$(oc get route central -n stackrox -o go-template='{{.spec.host}}'):443"
done
export ROX_CENTRAL_HOSTNAME="$ROX_CENTRAL_ADDRESS"
echo "========================================================================"
echo " Retrieving an API Token for Red Hat ACS"
echo "========================================================================"
echo
if ! oc get secret stackrox-api-token -n stackrox &>/dev/null; then
POLICY_JSON='{ "name": "init-token", "role":"Admin"}'
APIURL="https://$ROX_CENTRAL_ADDRESS/v1/apitokens/generate"
export ROX_API_TOKEN=$(curl -s -k -u admin:$ROX_ADMIN_PASSWORD -H 'Content-Type: application/json' -X POST -d "$POLICY_JSON" "$APIURL" | jq -r '.token')
oc create secret generic stackrox-api-token -n stackrox --from-literal=token="$ROX_API_TOKEN"
else
export ROX_API_TOKEN="$(oc get secret stackrox-api-token -n stackrox -o go-template --template='{{.data.token|base64decode}}')"
fi
echo "========================================================================"
echo " Generating the Cluster Init Bundle"
echo "========================================================================"
echo
if ! oc get secret admission-control-tls -n stackrox &>/dev/null; then
roxctl -e "$ROX_CENTRAL_ADDRESS" central init-bundles generate local-cluster --output-secrets /tmp/cluster_init_bundle.yaml
oc apply -f /tmp/cluster_init_bundle.yaml -n stackrox
fi
echo "========================================================================"
echo " Fixing OAuth Authentication"
echo "========================================================================"
echo
oc annotate -n stackrox serviceaccounts/central serviceaccounts.openshift.io/oauth-redirectreference.alt='{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"central-plain"}}' serviceaccounts.openshift.io/oauth-redirecturi.alt=sso/providers/openshift/callback
exit 0

5
charts/rhacs/templates/_helpers.tpl

@ -0,0 +1,5 @@
{{/* vim: set filetype=mustache: */}}
{{- define "acs-admin-password" -}}
{{- trunc 16 (sha256sum (cat .Values.masterKey "acs-admin-password")) -}}
{{- end -}}

116
charts/rhacs/templates/acs.yaml

@ -0,0 +1,116 @@
apiVersion: v1
kind: Namespace
metadata:
annotations:
argocd.argoproj.io/sync-wave: "10"
openshift.io/description: ""
openshift.io/display-name: ""
labels:
kubernetes.io/metadata.name: stackrox
name: stackrox
spec:
finalizers:
- kubernetes
---
apiVersion: v1
kind: Secret
metadata:
# The secret needs to be created before the creation of the "Central" Custom Resource.
# Otherwise, a race condition is possible and the installation of the Central might get stuck.
annotations:
argocd.argoproj.io/sync-wave: "10"
name: central-admin
namespace: stackrox
type: Opaque
data:
password: {{ include "acs-admin-password" . | b64enc | quote }}
---
apiVersion: platform.stackrox.io/v1alpha1
kind: Central
metadata:
annotations:
argocd.argoproj.io/sync-wave: "15"
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
name: stackrox-central-services
namespace: stackrox
spec:
central:
exposure:
loadBalancer:
enabled: false
port: 443
nodePort:
enabled: false
route:
enabled: true
adminPasswordSecret:
name: central-admin
db:
isEnabled: Default
persistence:
persistentVolumeClaim:
claimName: central-db
persistence:
persistentVolumeClaim:
claimName: stackrox-db
egress:
connectivityPolicy: Online
scanner:
analyzer:
scaling:
autoScaling: Disabled
replicas: 3
scannerComponent: Enabled
# Listen on pain HTTP so that we can expose the central through a Route
customize:
envVars:
- name: ROX_PLAINTEXT_ENDPOINTS
value: http@8080
---
apiVersion: platform.stackrox.io/v1alpha1
kind: SecuredCluster
metadata:
annotations:
argocd.argoproj.io/sync-wave: "30"
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
name: stackrox-secured-cluster-services
namespace: stackrox
spec:
auditLogs:
collection: Auto
admissionControl:
listenOnUpdates: true
bypass: BreakGlassAnnotation
contactImageScanners: ScanIfMissing
listenOnCreates: true
timeoutSeconds: 20
listenOnEvents: true
scanner:
analyzer:
scaling:
autoScaling: Enabled
maxReplicas: 5
minReplicas: 2
replicas: 3
scannerComponent: AutoSense
perNode:
collector:
collection: EBPF
imageFlavor: Regular
taintToleration: TolerateTaints
clusterName: local-cluster
---
apiVersion: console.openshift.io/v1
kind: ConsoleLink
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: rhacs-menu
spec:
applicationMenu:
imageURL: >-
/static/assets/redhat.svg
section: RHACS Section
href: 'https://central.{{ .Values.openshiftDnsZone }}/'
location: ApplicationMenu
text: Red Hat Advanced Cluster Security

151
charts/rhacs/templates/hook.yaml

@ -0,0 +1,151 @@
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-hook
namespace: stackrox
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-hook
namespace: stackrox
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: edit
subjects:
- kind: ServiceAccount
name: stackrox-hook
namespace: stackrox
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-hook-scc
namespace: stackrox
rules:
- apiGroups:
- security.openshift.io
resourceNames:
- anyuid
resources:
- securitycontextconstraints
verbs:
- use
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-hook-scc
namespace: stackrox
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: stackrox-hook-scc
subjects:
- kind: ServiceAccount
name: stackrox-hook
namespace: stackrox
---
apiVersion: v1
kind: ConfigMap
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-init-hook
namespace: stackrox
data:
{{ (.Files.Glob "files/stackrox-init-hook/*").AsConfig | indent 2 }}
---
apiVersion: v1
kind: ConfigMap
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-configure-hook
namespace: stackrox
data:
{{ (.Files.Glob "files/stackrox-configure-hook/*").AsConfig | indent 2 }}
---
apiVersion: batch/v1
kind: Job
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-init-hook
namespace: stackrox
spec:
backoffLimit: 30
template:
spec:
containers:
- name: hook
command:
- /entrypoint/configure-acs.sh
args: []
image: registry.redhat.io/openshift4/ose-cli:v4.13
imagePullPolicy: IfNotPresent
env:
- name: ROX_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: central-admin
key: password
- name: USER
value: openshift
- name: HOME
value: /tmp
volumeMounts:
- mountPath: /entrypoint
name: stackrox-hook
readOnly: true
serviceAccountName: stackrox-hook
serviceAccount: stackrox-hook
restartPolicy: OnFailure
terminationGracePeriodSeconds: 30
volumes:
- name: stackrox-hook
configMap:
name: stackrox-init-hook
defaultMode: 0755
---
apiVersion: batch/v1
kind: Job
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-configure-hook
namespace: stackrox
spec:
backoffLimit: 30
template:
spec:
containers:
- name: hook
command:
- /playbooks/entrypoint.sh
args: []
image: registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:1.0
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /playbooks
name: stackrox-hook
readOnly: true
workingDir: /playbooks
serviceAccountName: stackrox-hook
serviceAccount: stackrox-hook
restartPolicy: OnFailure
terminationGracePeriodSeconds: 30
volumes:
- name: stackrox-hook
configMap:
name: stackrox-configure-hook
defaultMode: 0755

37
charts/rhacs/templates/operator.yaml

@ -0,0 +1,37 @@
apiVersion: v1
kind: Namespace
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0"
openshift.io/description: ""
openshift.io/display-name: ""
labels:
kubernetes.io/metadata.name: rhacs-operator
name: rhacs-operator
spec:
finalizers:
- kubernetes
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0"
name: rhacs-operator
namespace: rhacs-operator
spec:
upgradeStrategy: Default
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
annotations:
argocd.argoproj.io/sync-wave: "10"
name: rhacs-operator
namespace: rhacs-operator
spec:
channel: rhacs-4.2
installPlanApproval: Automatic
name: rhacs-operator
source: redhat-operators
sourceNamespace: openshift-marketplace

24
charts/rhacs/templates/registry-reader.yaml

@ -0,0 +1,24 @@
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-registry-reader
namespace: stackrox
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: stackrox-registry-reader
namespace: stackrox
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:image-puller
subjects:
- kind: ServiceAccount
name: stackrox-registry-reader
namespace: stackrox
---

55
charts/rhacs/templates/route.yaml

@ -0,0 +1,55 @@
kind: Service
apiVersion: v1
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: central-plain
namespace: stackrox
spec:
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
type: ClusterIP
sessionAffinity: None
selector:
app: central
---
kind: Route
apiVersion: route.openshift.io/v1
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: central-plain
namespace: stackrox
spec:
host: central.{{ .Values.openshiftDnsZone }}
to:
kind: Service
name: central-plain
weight: 100
port:
targetPort: 8080
tls:
termination: edge
insecureEdgeTerminationPolicy: Redirect
wildcardPolicy: None
---
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
annotations:
argocd.argoproj.io/sync-wave: "20"
name: allow-ext-to-central-plain
namespace: stackrox
spec:
podSelector:
matchLabels:
app: central
ingress:
- ports:
- protocol: TCP
port: 8080
policyTypes:
- Ingress

5
charts/rhacs/values.yaml

@ -0,0 +1,5 @@
# DNS Zone delegated to OpenShift (ex: apps.foo.bar)
openshiftDnsZone: ""
# Master Key used to generate the RHACS admin password
masterKey: "S3cr3t!"
Loading…
Cancel
Save