- 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: Get Cosign public key kubernetes.core.k8s_info: api_version: v1 kind: Secret name: code-signature namespace: fruits-dev register: cosign_secret failed_when: cosign_secret.resources|length == 0 until: cosign_secret is succeeded retries: 60 delay: 5 - set_fact: cosign_public_key: '{{ cosign_secret.resources[0].data["cosign.pub"] | 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: Find signature integrations uri: url: '{{ acs_api }}/signatureintegrations' validate_certs: '{{ validate_certs }}' url_username: admin url_password: '{{ central_admin_password }}' force_basic_auth: yes register: find_signature_integrations_response changed_when: false - set_fact: signature_integration_id: '{{ (find_signature_integrations_response.json | json_query(query) | first).id }}' when: find_signature_integrations_response.json | json_query(query) | count > 0 vars: query: integrations[?name == `Sigstore`] - name: Create the Cosign signature integration uri: url: '{{ acs_api }}/signatureintegrations' 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_signature_integration_response changed_when: create_signature_integration_response.status == 200 when: signature_integration_id is not defined vars: integration: name: Sigstore cosign: publicKeys: - name: cosign.pub publicKeyPemEnc: '{{ cosign_public_key }}' - set_fact: signature_integration_id: '{{ create_signature_integration_response.json.id }}' when: signature_integration_id is not defined - debug: var: signature_integration_id - name: Find policies uri: url: '{{ acs_api }}/policies?query=Policy%3AImage%20is%20not%20signed' validate_certs: '{{ validate_certs }}' url_username: admin url_password: '{{ central_admin_password }}' force_basic_auth: yes register: find_policies_response changed_when: false - set_fact: policy_id: '{{ (find_policies_response.json.policies | first).id }}' when: find_policies_response.json.policies | count > 0 - name: Create the policy uri: url: '{{ acs_api }}/policies' method: POST status_code: "200" validate_certs: '{{ validate_certs }}' url_username: admin url_password: '{{ central_admin_password }}' body: '{{ policy }}' body_format: json force_basic_auth: yes register: create_policy_response changed_when: create_policy_response.status == 200 when: policy_id is not defined vars: policy: SORTEnforcement: no SORTLifecycleStage: '' SORTName: '' categories: - Security Best Practices criteriaLocked: no description: The container image has not been digitally signed. disabled: no enforcementActions: - SCALE_TO_ZERO_ENFORCEMENT - UNSATISFIABLE_NODE_CONSTRAINT_ENFORCEMENT eventSource: NOT_APPLICABLE exclusions: [] isDefault: no lifecycleStages: - DEPLOY mitreAttackVectors: [] mitreVectorsLocked: no name: Image is not signed notifiers: [] policySections: - policyGroups: - booleanOperator: OR fieldName: Image Signature Verified By negate: no values: - value: "{{ signature_integration_id }}" sectionName: Policy Section 1 policyVersion: '1.1' rationale: The container image MUST be digitally signed in order to prevent tampering. remediation: Use cosign to sign this image. See https://docs.sigstore.dev/cosign/signing_with_containers/ scope: - cluster: label: key: app value: fruits namespace: fruits-test - cluster: label: key: app value: fruits namespace: fruits-prod severity: CRITICAL_SEVERITY - set_fact: policy_id: '{{ create_policy_response.json.id }}' when: policy_id is not defined - debug: var: policy_id