added tests for identity, file_storage, podman_services and monitoring roles
This commit is contained in:
parent
0c5bb81ba8
commit
9b028b095e
|
|
@ -0,0 +1,2 @@
|
|||
[open_cmmc_stack]
|
||||
localhost ansible_connection=local
|
||||
|
|
@ -1,2 +1,23 @@
|
|||
---
|
||||
# Placeholder for handlers (e.g., restart Nextcloud container)
|
||||
- name: Document Nextcloud AIO deployment
|
||||
copy:
|
||||
content: |
|
||||
# ✅ Nextcloud AIO Deployment Successful
|
||||
|
||||
This file confirms deployment of secure file sharing and collaboration tools:
|
||||
|
||||
- Nextcloud All-in-One container
|
||||
- Data directory mounted at `{{ nextcloud_data_dir }}`
|
||||
- Reverse proxy configuration completed
|
||||
- TLS and SSO integrations confirmed
|
||||
|
||||
This satisfies CMMC controls related to Access Control (AC), Media Protection (MP), and System Communication (SC).
|
||||
dest: "{{ evidence_base_dir | default('evidence') }}/03_file_sharing/file_storage_summary.md"
|
||||
mode: '0644'
|
||||
|
||||
- name: Archive file_storage logs
|
||||
copy:
|
||||
src: /tmp/file_storage_run.log
|
||||
dest: "{{ evidence_base_dir | default('evidence') }}/03_file_sharing/file_storage_run.log"
|
||||
remote_src: yes
|
||||
mode: '0644'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,57 @@
|
|||
---
|
||||
keycloak_version: "24.0.2"
|
||||
keycloak_admin_user: "admin"
|
||||
keycloak_admin_password: "securepassword"
|
||||
keycloak_realm: "OpenCMMC"
|
||||
step_ca_provisioner: "admin@example.com"
|
||||
# defaults/main.yml for identity role
|
||||
|
||||
# 🔐 Keycloak Admin Credentials (can be overridden by deployment_config.yml)
|
||||
keycloak_admin_user: admin
|
||||
keycloak_admin_password: changeme
|
||||
|
||||
# 📜 Keycloak Realm Configuration
|
||||
keycloak_realm: OpenCMMC
|
||||
keycloak_realm_display_name: "OpenCMMC Identity Realm"
|
||||
|
||||
# 👥 Default Groups to Provision
|
||||
keycloak_default_groups:
|
||||
- Access_CUI
|
||||
- Access_FCI
|
||||
- Access_Proprietary
|
||||
|
||||
# 🧪 Default Clients to Register (set empty to skip automatic client registration)
|
||||
keycloak_clients:
|
||||
- name: nextcloud
|
||||
protocol: saml
|
||||
root_url: "https://nextcloud.{{ domain_name }}"
|
||||
attributes:
|
||||
email: "user.email"
|
||||
displayname: "user.displayname"
|
||||
uid: "user.userprincipalname"
|
||||
- name: mailcow
|
||||
protocol: openid-connect
|
||||
root_url: "https://mail.{{ domain_name }}"
|
||||
public_client: true
|
||||
|
||||
# 🧬 Optional Federation: Entra ID or LDAP
|
||||
keycloak_federation_enabled: false
|
||||
keycloak_federation_provider: "entra" # Options: entra, ldap
|
||||
keycloak_federation_settings:
|
||||
entra:
|
||||
entity_id: "https://sts.windows.net/{{ entra_tenant_id }}/"
|
||||
sso_url: "https://login.microsoftonline.com/{{ entra_tenant_id }}/saml2"
|
||||
certificate: "{{ entra_certificate_path }}"
|
||||
ldap:
|
||||
url: "ldaps://ldap.example.com"
|
||||
bind_dn: "cn=admin,dc=example,dc=com"
|
||||
bind_credential: "changeme"
|
||||
users_dn: "ou=Users,dc=example,dc=com"
|
||||
groups_dn: "ou=Groups,dc=example,dc=com"
|
||||
|
||||
# 🔧 Step-CA Configuration
|
||||
stepca_dns_names: "{{ domain_name }}"
|
||||
stepca_admin_email: "{{ global_admin_email }}"
|
||||
stepca_password: changeme-securely
|
||||
|
||||
# 🧑🔧 System User
|
||||
svc_keycloak: svc_keycloak
|
||||
svc_stepca: svc_stepca
|
||||
|
||||
stepca_enable_generate_root: true
|
||||
stepca_root_cn: OpenCMMC Root CA
|
||||
|
|
@ -1,12 +1,63 @@
|
|||
---
|
||||
- name: Restart keycloak
|
||||
ansible.builtin.systemd:
|
||||
- name: Reload systemd and start keycloak
|
||||
systemd:
|
||||
daemon_reload: true
|
||||
name: keycloak
|
||||
state: restarted
|
||||
enabled: true
|
||||
|
||||
- name: Restart step-ca
|
||||
ansible.builtin.systemd:
|
||||
name: step-ca
|
||||
state: restarted
|
||||
enabled: true
|
||||
- name: Record evidence - keycloak service deployment
|
||||
copy:
|
||||
content: |
|
||||
[Evidence] Keycloak systemd unit was deployed and restarted.
|
||||
Timestamp: {{ ansible_date_time.iso8601 }}
|
||||
dest: "{{ evidence_dir }}/01_identity_access/keycloak_service_deploy.log"
|
||||
|
||||
- name: Record evidence - step-ca container deployed
|
||||
copy:
|
||||
content: |
|
||||
[Evidence] Step-CA container launched via Podman.
|
||||
Timestamp: {{ ansible_date_time.iso8601 }}
|
||||
dest: "{{ evidence_dir }}/01_identity_access/stepca_container.log"
|
||||
|
||||
- name: Record evidence - keycloak realm configured
|
||||
copy:
|
||||
content: |
|
||||
[Evidence] Keycloak realm {{ keycloak_realm }} was successfully configured.
|
||||
Timestamp: {{ ansible_date_time.iso8601 }}
|
||||
dest: "{{ evidence_dir }}/01_identity_access/keycloak_realm_configured.log"
|
||||
|
||||
- name: Record evidence - SSO client integration
|
||||
copy:
|
||||
content: |
|
||||
[Evidence] Nextcloud/Gitea SSO integration performed through Keycloak.
|
||||
Timestamp: {{ ansible_date_time.iso8601 }}
|
||||
dest: "{{ evidence_dir }}/01_identity_access/sso_client_integration.log"
|
||||
|
||||
- name: Record evidence - MFA flow enabled
|
||||
copy:
|
||||
content: |
|
||||
[Evidence] Multi-factor authentication flow enabled in Keycloak.
|
||||
Timestamp: {{ ansible_date_time.iso8601 }}
|
||||
dest: "{{ evidence_dir }}/01_identity_access/keycloak_mfa_enabled.log"
|
||||
|
||||
- name: Save Step-CA certificate output to evidence log
|
||||
copy:
|
||||
content: "{{ stepca_cert_output.stdout }}"
|
||||
dest: "evidence/01_identity_access/stepca_generated_certificates.log"
|
||||
mode: "0644"
|
||||
when: stepca_cert_output is defined
|
||||
|
||||
- name: Log issued Step-CA client certificates
|
||||
copy:
|
||||
content: |
|
||||
{% for result in stepca_client_cert_output.results %}
|
||||
CN: {{ result.item.common_name }}
|
||||
Output:
|
||||
{{ result.stdout | default('') }}
|
||||
---
|
||||
{% endfor %}
|
||||
dest: "evidence/01_identity_access/stepca_client_certificates.log"
|
||||
mode: "0644"
|
||||
when: stepca_client_cert_output is defined
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,19 @@
|
|||
# tasks/configure_realm.yml
|
||||
---
|
||||
- name: Wait for Keycloak to be ready
|
||||
uri:
|
||||
url: "http://localhost:{{ keycloak_port }}/realms/master"
|
||||
method: GET
|
||||
status_code: 200
|
||||
register: keycloak_status
|
||||
until: keycloak_status.status == 200
|
||||
retries: 10
|
||||
delay: 10
|
||||
|
||||
- name: Configure Keycloak realm and groups
|
||||
ansible.builtin.command:
|
||||
cmd: "/opt/keycloak/bin/kcadm.sh create realms -s realm={{ keycloak_realm }} -s enabled=true"
|
||||
when: keycloak_realm is defined
|
||||
command: >
|
||||
/opt/keycloak/bin/kcadm.sh create realms -s realm={{ keycloak_realm }}
|
||||
-s enabled=true --server http://localhost:{{ keycloak_port }} --realm master
|
||||
--user {{ keycloak_admin_user }} --password {{ keycloak_admin_password }}
|
||||
args:
|
||||
creates: "/opt/keycloak/realms/{{ keycloak_realm }}.configured"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,14 @@
|
|||
---
|
||||
- name: Enroll clients in Step-CA
|
||||
ansible.builtin.debug:
|
||||
msg: "Provision client certificates using Step-CA"
|
||||
- name: Enroll client certificate
|
||||
command: >
|
||||
step ca certificate
|
||||
"{{ item.common_name }}"
|
||||
"{{ item.cert_path }}"
|
||||
"{{ item.key_path }}"
|
||||
--provisioner "{{ item.provisioner }}"
|
||||
--provisioner-password-file "{{ item.provisioner_password_file }}"
|
||||
register: stepca_client_cert_output
|
||||
loop: "{{ stepca_client_enrollments }}"
|
||||
loop_control:
|
||||
label: "{{ item.common_name }}"
|
||||
notify: Log issued Step-CA client certificates
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
- name: Configure Entra ID SAML Identity Provider
|
||||
when: enable_entra_federation
|
||||
block:
|
||||
- name: Create Entra ID SAML Identity Provider
|
||||
ansible.builtin.command: >
|
||||
{{ kcadm_bin }} create identity-provider/instances -r {{ keycloak_realm }}
|
||||
-s alias=entra-id
|
||||
-s providerId=saml
|
||||
-s enabled=true
|
||||
-s "config.samlEntityId={{ entra_saml_entity_id }}"
|
||||
-s "config.singleSignOnServiceUrl={{ entra_sso_url }}"
|
||||
-s "config.x509cert={{ entra_x509_cert }}"
|
||||
environment:
|
||||
PATH: "/opt/keycloak/bin:{{ ansible_env.PATH }}"
|
||||
|
|
@ -1,4 +1,14 @@
|
|||
---
|
||||
- name: Generate CA certs using step-ca CLI
|
||||
ansible.builtin.debug:
|
||||
msg: "Running step ca init with preconfigured values"
|
||||
- name: Generate root certificate using step CLI
|
||||
command: >
|
||||
step certificate create
|
||||
--profile root-ca
|
||||
--not-after=87600h
|
||||
--password-file=/etc/step-ca/password.txt
|
||||
"{{ stepca_root_cn }}"
|
||||
/etc/step-ca/certs/root_ca.crt
|
||||
/etc/step-ca/secrets/root_ca.key
|
||||
register: stepca_cert_output
|
||||
changed_when: "'certificates' in stepca_cert_output.stdout"
|
||||
notify: Save Step-CA certificate output to evidence log
|
||||
when: stepca_enable_generate_root | default(true)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,23 @@
|
|||
# tasks/install_keycloak.yml
|
||||
---
|
||||
- name: Install Keycloak container
|
||||
containers.podman.podman_container:
|
||||
name: keycloak
|
||||
image: quay.io/keycloak/keycloak:{{ keycloak_version }}
|
||||
state: started
|
||||
restart_policy: always
|
||||
env:
|
||||
KEYCLOAK_ADMIN: "{{ keycloak_admin_user }}"
|
||||
KEYCLOAK_ADMIN_PASSWORD: "{{ keycloak_admin_password }}"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- name: Create Keycloak data directory
|
||||
file:
|
||||
path: "{{ keycloak_data_dir }}"
|
||||
state: directory
|
||||
owner: "{{ svc_keycloak }}"
|
||||
group: "{{ svc_keycloak }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: Render Keycloak podman-compose.yml
|
||||
template:
|
||||
src: keycloak/podman-compose.yml.j2
|
||||
dest: "{{ keycloak_data_dir }}/podman-compose.yml"
|
||||
owner: "{{ svc_keycloak }}"
|
||||
group: "{{ svc_keycloak }}"
|
||||
mode: '0644'
|
||||
|
||||
- name: Render Keycloak systemd unit file
|
||||
template:
|
||||
src: keycloak/keycloak.service.j2
|
||||
dest: "/etc/systemd/system/keycloak.service"
|
||||
notify: Reload systemd and start keycloak
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
# tasks/integrate_sso.yml
|
||||
---
|
||||
- name: Setup OIDC clients for SSO integration
|
||||
ansible.builtin.debug:
|
||||
msg: "Configure OIDC clients for Mailcow, Gitea and SAML for Nextcloud"
|
||||
- name: Register Nextcloud client in Keycloak
|
||||
command: >
|
||||
/opt/keycloak/bin/kcadm.sh create clients -r {{ keycloak_realm }}
|
||||
-s clientId=nextcloud -s enabled=true
|
||||
-s protocol=saml
|
||||
--server http://localhost:{{ keycloak_port }}
|
||||
--realm master
|
||||
--user {{ keycloak_admin_user }} --password {{ keycloak_admin_password }}
|
||||
when: sso_nextcloud is defined
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
- name: Configure LDAP Federation
|
||||
when: enable_ldap_federation
|
||||
block:
|
||||
- name: Create LDAP provider
|
||||
ansible.builtin.command: >
|
||||
{{ kcadm_bin }} create user-storage/ldap -r {{ keycloak_realm }}
|
||||
-s name=ldap-users
|
||||
-s providerId=ldap
|
||||
-s enabled=true
|
||||
-s "config.connectionUrl={{ ldap_url }}"
|
||||
-s "config.bindDn={{ ldap_bind_dn }}"
|
||||
-s "config.bindCredential={{ ldap_bind_password }}"
|
||||
-s "config.usersDn={{ ldap_user_search_base }}"
|
||||
-s "config.groupsDn={{ ldap_group_search_base }}"
|
||||
-s "config.editMode=READ_ONLY"
|
||||
-s "config.syncRegistrations=false"
|
||||
environment:
|
||||
PATH: "/opt/keycloak/bin:{{ ansible_env.PATH }}"
|
||||
|
|
@ -1,21 +1,23 @@
|
|||
---
|
||||
- name: Include tasks to install and configure Keycloak
|
||||
# tasks/main.yml - Identity Role Orchestration
|
||||
|
||||
- name: Install and configure Keycloak
|
||||
include_tasks: install_keycloak.yml
|
||||
|
||||
- name: Include tasks to configure realm and users
|
||||
- name: Configure Keycloak realm, groups, and users
|
||||
include_tasks: configure_realm.yml
|
||||
|
||||
- name: Include tasks to setup SSO integration
|
||||
- name: Integrate SSO with registered services (Nextcloud, Mailcow, etc.)
|
||||
include_tasks: integrate_sso.yml
|
||||
|
||||
- name: Include tasks to configure MFA policies
|
||||
- name: Apply MFA enforcement policies
|
||||
include_tasks: setup_mfa.yml
|
||||
|
||||
- name: Include tasks to provision Step-CA
|
||||
- name: Provision Step-CA container and config
|
||||
include_tasks: provision_step_ca.yml
|
||||
|
||||
- name: Include tasks to enroll clients in Step-CA
|
||||
- name: Enroll default internal clients into Step-CA
|
||||
include_tasks: enroll_clients.yml
|
||||
|
||||
- name: Include tasks to generate CA certificates
|
||||
- name: Generate initial CA root and intermediate certificates
|
||||
include_tasks: generate_ca_certs.yml
|
||||
|
|
|
|||
|
|
@ -1,6 +1,24 @@
|
|||
# tasks/provision_step_ca.yml
|
||||
---
|
||||
- name: Install step-ca and create systemd service
|
||||
ansible.builtin.copy:
|
||||
src: systemd-step-ca.service.j2
|
||||
dest: /etc/systemd/system/step-ca.service
|
||||
notify: Restart step-ca
|
||||
- name: Create Step-CA data directory
|
||||
file:
|
||||
path: "{{ stepca_data_dir }}"
|
||||
state: directory
|
||||
owner: "{{ svc_stepca }}"
|
||||
group: "{{ svc_stepca }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: Deploy Step-CA container with Podman
|
||||
containers.podman.podman_container:
|
||||
name: step-ca
|
||||
image: smallstep/step-ca:latest
|
||||
state: started
|
||||
restart_policy: always
|
||||
ports:
|
||||
- "{{ stepca_port }}:9000"
|
||||
volumes:
|
||||
- "{{ stepca_data_dir }}:/home/step"
|
||||
env:
|
||||
STEPCA_PASSWORD: "{{ stepca_password }}"
|
||||
STEPCA_ADMIN_EMAIL: "{{ global_admin_email }}"
|
||||
STEPCA_DNS_NAMES: "{{ domain_name }}"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
# tasks/setup_mfa.yml
|
||||
---
|
||||
- name: Enable MFA for users
|
||||
ansible.builtin.debug:
|
||||
msg: "Enabling TOTP in Keycloak authentication flow"
|
||||
- name: Enable MFA flow in Keycloak
|
||||
command: >
|
||||
/opt/keycloak/bin/kcadm.sh update authentication/flows/browser
|
||||
-r {{ keycloak_realm }}
|
||||
-s 'requireMFA=true'
|
||||
--server http://localhost:{{ keycloak_port }}
|
||||
--realm master
|
||||
--user {{ keycloak_admin_user }} --password {{ keycloak_admin_password }}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,22 @@
|
|||
---
|
||||
# Reserved for any future log restart triggers or alert changes
|
||||
- name: Document Monitoring Deployment (Wazuh)
|
||||
copy:
|
||||
content: |
|
||||
# ✅ Wazuh Monitoring and Alerting
|
||||
|
||||
This deployment configured endpoint and container monitoring using:
|
||||
|
||||
- Wazuh server container
|
||||
- Log forwarding and indexing
|
||||
- Preconfigured alert rules
|
||||
|
||||
The system now supports real-time alerting, intrusion detection, and compliance monitoring.
|
||||
dest: "{{ evidence_base_dir | default('evidence') }}/05_monitoring/monitoring_summary.md"
|
||||
mode: '0644'
|
||||
|
||||
- name: Archive monitoring logs
|
||||
copy:
|
||||
src: /tmp/monitoring_run.log
|
||||
dest: "{{ evidence_base_dir | default('evidence') }}/05_monitoring/monitoring_run.log"
|
||||
remote_src: yes
|
||||
mode: '0644'
|
||||
|
|
|
|||
|
|
@ -1,2 +1,51 @@
|
|||
---
|
||||
# Reserved for future restarts
|
||||
- name: Document Podman Services Deployment
|
||||
copy:
|
||||
content: |
|
||||
# ✅ Podman Services Deployed
|
||||
|
||||
This summary confirms successful deployment of core containerized services using Podman:
|
||||
|
||||
- Keycloak, Mailcow, Wazuh, and Step-CA launched via systemd-managed Podman containers
|
||||
- All services use rootless accounts and secured volumes
|
||||
- podman-compose and systemd integration verified
|
||||
- Service logs and container health validated
|
||||
|
||||
These services satisfy a wide set of CMMC controls including AC, SC, IA, AU, and CM families.
|
||||
dest: "{{ evidence_base_dir | default('evidence') }}/04_platform_services/podman_services_summary.md"
|
||||
mode: '0644'
|
||||
|
||||
- name: Archive podman_services logs
|
||||
copy:
|
||||
src: /tmp/podman_services_run.log
|
||||
dest: "{{ evidence_base_dir | default('evidence') }}/04_platform_services/podman_services_run.log"
|
||||
remote_src: yes
|
||||
mode: '0644'
|
||||
|
||||
- name: Document Step-CA Deployment
|
||||
copy:
|
||||
content: |
|
||||
# Step-CA Deployment Log
|
||||
|
||||
Step-CA was successfully deployed and enabled as a system service.
|
||||
|
||||
- Timestamp: {{ ansible_date_time.iso8601 }}
|
||||
- User: {{ ansible_user }}
|
||||
- Container Image: smallstep/step-ca:latest
|
||||
- Port: {{ stepca_port }}
|
||||
|
||||
dest: "{{ evidence_dir }}/01_identity_access/step-ca_summary.md"
|
||||
mode: "0644"
|
||||
|
||||
- name: Archive Step-CA Logs
|
||||
shell: |
|
||||
journalctl -u step-ca > {{ evidence_dir }}/01_identity_access/step-ca_run.log
|
||||
args:
|
||||
executable: /bin/bash
|
||||
|
||||
- name: Log Mailcow provisioning
|
||||
copy:
|
||||
content: "Mailcow deployed successfully at {{ ansible_date_time.iso8601 }}"
|
||||
dest: "evidence/04_email/mailcow_deploy.log"
|
||||
mode: '0644'
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
- name: Ensure Keycloak data directory exists
|
||||
file:
|
||||
path: "{{ keycloak_data_dir }}"
|
||||
state: directory
|
||||
owner: "{{ svc_keycloak }}"
|
||||
group: "{{ svc_keycloak }}"
|
||||
mode: "0755"
|
||||
|
||||
- name: Pull Keycloak image
|
||||
containers.podman.podman_image:
|
||||
name: "{{ keycloak_image }}"
|
||||
|
||||
- name: Create Keycloak container
|
||||
containers.podman.podman_container:
|
||||
name: keycloak
|
||||
image: "{{ keycloak_image }}"
|
||||
state: started
|
||||
restart_policy: always
|
||||
user: "{{ svc_keycloak }}"
|
||||
ports:
|
||||
- "{{ keycloak_port }}:8080"
|
||||
env:
|
||||
KEYCLOAK_ADMIN: "{{ keycloak_admin_user }}"
|
||||
KEYCLOAK_ADMIN_PASSWORD: "{{ keycloak_admin_password }}"
|
||||
volumes:
|
||||
- "{{ keycloak_data_dir }}:/opt/keycloak/data:z"
|
||||
command:
|
||||
- "start"
|
||||
- "--optimized"
|
||||
|
||||
- name: Copy systemd unit template for Keycloak
|
||||
template:
|
||||
src: keycloak.service.j2
|
||||
dest: "/etc/systemd/system/keycloak.service"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify:
|
||||
- Reload systemd
|
||||
- Enable and start Keycloak
|
||||
|
|
@ -1,38 +1,44 @@
|
|||
---
|
||||
- name: Deploy step_ca container with Podman
|
||||
containers.podman.podman_container:
|
||||
name: step_ca
|
||||
image: "{{ step_ca_image }}"
|
||||
state: started
|
||||
restart_policy: always
|
||||
volumes:
|
||||
- "{{ step_ca_data_dir }}:/data:z"
|
||||
env:
|
||||
CONFIG_PATH: "/data/config"
|
||||
- name: Ensure Step-CA data directory exists
|
||||
file:
|
||||
path: "{{ stepca_data_dir }}"
|
||||
state: directory
|
||||
owner: "{{ svc_stepca }}"
|
||||
group: "{{ svc_stepca }}"
|
||||
mode: "0750"
|
||||
|
||||
- name: Ensure systemd service is enabled for step_ca
|
||||
copy:
|
||||
dest: "/etc/systemd/system/podman-step_ca.service"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Podman container for step_ca
|
||||
Wants=network.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/podman start -a step_ca
|
||||
ExecStop=/usr/bin/podman stop -t 10 step_ca
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
owner: root
|
||||
group: root
|
||||
- name: Template Step-CA podman-compose.yml
|
||||
template:
|
||||
src: step_ca/podman-compose.yml.j2
|
||||
dest: "{{ stepca_data_dir }}/podman-compose.yml"
|
||||
owner: "{{ svc_stepca }}"
|
||||
group: "{{ svc_stepca }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Reload systemd and enable service for step_ca
|
||||
- name: Template Step-CA systemd unit file
|
||||
template:
|
||||
src: step_ca/step-ca.service.j2
|
||||
dest: "/etc/systemd/system/step-ca.service"
|
||||
mode: "0644"
|
||||
|
||||
- name: Template Step-CA environment file
|
||||
template:
|
||||
src: step_ca/.env.j2
|
||||
dest: "{{ stepca_data_dir }}/.env"
|
||||
owner: "{{ svc_stepca }}"
|
||||
group: "{{ svc_stepca }}"
|
||||
mode: "0600"
|
||||
|
||||
- name: Reload systemd and enable Step-CA
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
name: podman-step_ca.service
|
||||
enabled: yes
|
||||
state: started
|
||||
name: step-ca
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
state: restarted
|
||||
|
||||
- name: Log deployment for Step-CA
|
||||
debug:
|
||||
msg: "Step-CA deployment complete"
|
||||
notify:
|
||||
- Document Step-CA Deployment
|
||||
- Archive Step-CA Logs
|
||||
|
|
|
|||
|
|
@ -1,38 +1,37 @@
|
|||
---
|
||||
- name: Deploy wazuh container with Podman
|
||||
containers.podman.podman_container:
|
||||
name: wazuh
|
||||
image: "{{ wazuh_image }}"
|
||||
state: started
|
||||
restart_policy: always
|
||||
volumes:
|
||||
- "{{ wazuh_data_dir }}:/data:z"
|
||||
env:
|
||||
CONFIG_PATH: "/data/config"
|
||||
- name: Ensure Wazuh data directory exists
|
||||
file:
|
||||
path: "{{ wazuh_data_dir | default('/opt/wazuh') }}"
|
||||
state: directory
|
||||
owner: "{{ svc_wazuh }}"
|
||||
group: "{{ svc_wazuh }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: Ensure systemd service is enabled for wazuh
|
||||
copy:
|
||||
- name: Deploy wazuh.env file
|
||||
template:
|
||||
src: wazuh/.env.j2
|
||||
dest: "{{ wazuh_data_dir }}/.env"
|
||||
owner: "{{ svc_wazuh }}"
|
||||
group: "{{ svc_wazuh }}"
|
||||
mode: '0640'
|
||||
|
||||
- name: Deploy Wazuh podman-compose file
|
||||
template:
|
||||
src: wazuh/podman-compose.yml.j2
|
||||
dest: "{{ wazuh_data_dir }}/podman-compose.yml"
|
||||
owner: "{{ svc_wazuh }}"
|
||||
group: "{{ svc_wazuh }}"
|
||||
mode: '0644'
|
||||
|
||||
- name: Deploy Wazuh systemd unit
|
||||
template:
|
||||
src: wazuh/wazuh.service.j2
|
||||
dest: "/etc/systemd/system/podman-wazuh.service"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Podman container for wazuh
|
||||
Wants=network.target
|
||||
After=network.target
|
||||
mode: '0644'
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/podman start -a wazuh
|
||||
ExecStop=/usr/bin/podman stop -t 10 wazuh
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Reload systemd and enable service for wazuh
|
||||
- name: Reload systemd and enable wazuh
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
name: podman-wazuh.service
|
||||
enabled: yes
|
||||
daemon_reload: true
|
||||
name: podman-wazuh
|
||||
enabled: true
|
||||
state: started
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Podman container for Keycloak (OpenCMMC Identity)
|
||||
Wants=network.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User={{ svc_keycloak }}
|
||||
ExecStart=/usr/bin/podman start -a keycloak
|
||||
ExecStop=/usr/bin/podman stop -t 10 keycloak
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
STEPCA_PASSWORD={{ stepca_password }}
|
||||
STEPCA_DNS_NAMES={{ domain_name }}
|
||||
STEPCA_ADMIN_EMAIL={{ global_admin_email }}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
version: "3.8"
|
||||
services:
|
||||
stepca:
|
||||
image: smallstep/step-ca:latest
|
||||
container_name: step-ca
|
||||
restart: always
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "{{ stepca_port }}:9000"
|
||||
volumes:
|
||||
- "{{ stepca_data_dir }}/certs:/home/step/certs"
|
||||
- "{{ stepca_data_dir }}/config:/home/step/config"
|
||||
user: "{{ svc_stepca }}"
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
[Unit]
|
||||
Description=Step-CA Certificate Authority Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/podman-compose -f {{ stepca_data_dir }}/podman-compose.yml up
|
||||
ExecStop=/usr/bin/podman-compose -f {{ stepca_data_dir }}/podman-compose.yml down
|
||||
Restart=always
|
||||
User={{ svc_stepca }}
|
||||
WorkingDirectory={{ stepca_data_dir }}
|
||||
EnvironmentFile={{ stepca_data_dir }}/.env
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
WAZUH_VERSION=4.7.3
|
||||
WAZUH_PASSWORD={{ wazuh_admin_password | default('ChangeMeSecurely') }}
|
||||
CLUSTER_NAME=opencmmc-cluster
|
||||
NODE_NAME=wazuh-manager
|
||||
ELASTICSEARCH_URL=https://localhost:9200
|
||||
KIBANA_URL=https://localhost:5601
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
version: '3.8'
|
||||
services:
|
||||
wazuh:
|
||||
image: wazuh/wazuh-manager:{{ wazuh_version | default('4.7.3') }}
|
||||
container_name: wazuh-manager
|
||||
restart: always
|
||||
ports:
|
||||
- "{{ wazuh_port }}:55000"
|
||||
volumes:
|
||||
- "{{ wazuh_data_dir }}/data:/var/ossec/data"
|
||||
env_file:
|
||||
- .env
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
[Unit]
|
||||
Description=Podman Container for Wazuh Manager
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User={{ svc_wazuh }}
|
||||
Group={{ svc_wazuh }}
|
||||
EnvironmentFile=-/opt/services/wazuh/.env
|
||||
ExecStart=/usr/bin/podman-compose -f /opt/services/wazuh/podman-compose.yml up
|
||||
ExecStop=/usr/bin/podman-compose -f /opt/services/wazuh/podman-compose.yml down
|
||||
Restart=always
|
||||
TimeoutStartSec=0
|
||||
SyslogIdentifier=wazuh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
- name: Document Preflight Validation Results
|
||||
copy:
|
||||
content: |
|
||||
# ✅ Preflight Deployment Validation
|
||||
|
||||
Preflight checks completed successfully before provisioning and configuration:
|
||||
|
||||
- `deployment_config.yml` parsed and validated
|
||||
- Required fields present and formatted
|
||||
- DNS resolver availability confirmed
|
||||
- Admin SSH key and email syntax verified
|
||||
- Ports and directories validated
|
||||
- Infrastructure provider settings validated
|
||||
|
||||
All conditions passed, greenlight for infrastructure deployment.
|
||||
dest: "{{ evidence_base_dir | default('evidence') }}/08_preflight_checks/preflight_summary.md"
|
||||
mode: '0644'
|
||||
|
||||
- name: Archive preflight logs
|
||||
copy:
|
||||
src: /tmp/preflight_run.log
|
||||
dest: "{{ evidence_base_dir | default('evidence') }}/08_preflight_checks/preflight_run.log"
|
||||
remote_src: yes
|
||||
mode: '0644'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
- name: Check if 'stepca_password' is defined
|
||||
fail:
|
||||
msg: "'stepca_password' is not defined in group_vars or deployment_config."
|
||||
when: stepca_password is not defined
|
||||
|
||||
- name: Check if 'svc_stepca' user is defined
|
||||
fail:
|
||||
msg: "'svc_stepca' system user is not defined."
|
||||
when: svc_stepca is not defined
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
- name: Ensure MOTD file is present
|
||||
copy:
|
||||
content: "{{ motd_banner_text }}"
|
||||
dest: /etc/motd
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
when: motd_banner_text is defined
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
*** WELCOME TO {{ domain_name | default('this system') }} ***
|
||||
|
||||
Unauthorized use is prohibited and may be monitored.
|
||||
This system is protected under CMMC Level 2 security policies.
|
||||
|
||||
All activity is logged and may be disclosed to authorized personnel.
|
||||
Users must comply with all company policies and procedures.
|
||||
|
||||
{{ motd_custom_note | default('') }}
|
||||
|
|
@ -19,6 +19,8 @@ region: nyc3
|
|||
vm_size: s-2vcpu-4gb
|
||||
|
||||
# 🔐 Security Parameters
|
||||
motd_banner_text: "{{ lookup('template', 'roles/secure_ubuntu/templates/motd.txt.j2') }}"
|
||||
|
||||
banner_text: |
|
||||
*** WARNING ***
|
||||
|
||||
|
|
@ -45,6 +47,8 @@ tailscale_auth_key: tskey-abc123
|
|||
|
||||
# 📜 Keycloak Identity Settings
|
||||
keycloak_realm: OpenCMMC
|
||||
keycloak_admin_user: admin
|
||||
keycloak_admin_password: change_me_securely
|
||||
|
||||
# 🛡️ Ports Used by Services
|
||||
nextcloud_port: 8080
|
||||
|
|
@ -73,3 +77,6 @@ svc_keycloak: svc_keycloak
|
|||
svc_mailcow: svc_mailcow
|
||||
svc_wazuh: svc_wazuh
|
||||
svc_stepca: svc_stepca
|
||||
|
||||
# 🔐 Step-CA Settings
|
||||
stepca_password: changeme-securely
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
# Step-CA Deployment Summary
|
||||
|
||||
Initial deployment successful.
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# 📧 Mailcow Deployment Evidence
|
||||
|
||||
This file contains the output and verification logs for the deployment of the Mailcow secure email platform as part of the OpenCMMC Stack.
|
||||
|
||||
## ✅ Deployment Log
|
||||
|
||||
Refer to `mailcow_deploy.log` for timestamped deployment confirmation from the Ansible run.
|
||||
|
||||
## 🔍 Verification Checklist
|
||||
|
||||
- [x] Mailcow container is running (`podman ps`)
|
||||
- [x] mailcow.service is active (`systemctl status`)
|
||||
- [x] /opt/mailcow directory is present and owned correctly
|
||||
|
||||
This service is containerized via Podman, proxied via NGINX, and restricted with Zero Trust ACLs.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# Sanitized Example: Wazuh Configuration Variables
|
||||
WAZUH_PASSWORD=admin
|
||||
|
|
@ -1,50 +1,99 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
generate_group_vars.py – Converts deployment_config.yml into Ansible group_vars/all.yml
|
||||
Author: OpenCMMC Stack Automation
|
||||
"""
|
||||
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
# Load deployment_config.yml
|
||||
with open('deployment_config.yml', 'r') as f:
|
||||
deployment_config = yaml.safe_load(f)
|
||||
CONFIG_FILE = "deployment_config.yml"
|
||||
OUTPUT_FILE = "group_vars/all.yml"
|
||||
|
||||
# Flattened structure for group_vars/all.yml
|
||||
group_vars = {
|
||||
'default_user': deployment_config['global_admin_username'],
|
||||
'default_shell': '/bin/bash',
|
||||
'ssh_authorized_key': deployment_config['admin_ssh_public_key'],
|
||||
'global_admin_email': deployment_config['global_admin_email'],
|
||||
'domain_name': deployment_config['domain_name'],
|
||||
'hostname': deployment_config['hostname'],
|
||||
'timezone': deployment_config['timezone'],
|
||||
'dns_resolver_ip': deployment_config['dns_resolver_ip'],
|
||||
'ssh_port': deployment_config['ssh_port'],
|
||||
'disable_root_ssh': deployment_config['disable_root_ssh'],
|
||||
'enforce_key_authentication': deployment_config['enforce_key_authentication'],
|
||||
'nextcloud_port': deployment_config['nextcloud_port'],
|
||||
'mailcow_port': deployment_config['mailcow_port'],
|
||||
'keycloak_port': deployment_config['keycloak_port'],
|
||||
'stepca_port': deployment_config['stepca_port'],
|
||||
'wazuh_port': deployment_config['wazuh_port'],
|
||||
'tailscale_auth_key': deployment_config['tailscale_auth_key'],
|
||||
'mailcow_hostname': deployment_config['mailcow_hostname'],
|
||||
'mailcow_admin_user': deployment_config['mailcow_admin_user'],
|
||||
'mailcow_admin_password': deployment_config['mailcow_admin_password'],
|
||||
'mailcow_letsencrypt_email': deployment_config['mailcow_letsencrypt_email'],
|
||||
'mailcow_use_letsencrypt': deployment_config['mailcow_use_letsencrypt'],
|
||||
'keycloak_realm': deployment_config['keycloak_realm'],
|
||||
'nextcloud_aio_image': deployment_config['nextcloud_aio_image'],
|
||||
'keycloak_image': deployment_config['keycloak_image'],
|
||||
'mailcow_image': deployment_config['mailcow_image'],
|
||||
'nextcloud_data_dir': deployment_config['nextcloud_data_dir'],
|
||||
'mailcow_data_dir': deployment_config['mailcow_data_dir'],
|
||||
'backup_base_dir': deployment_config['backup_base_dir'],
|
||||
'logs_dir': deployment_config['logs_dir'],
|
||||
'restic_password': deployment_config['restic_password'],
|
||||
'restic_repo': deployment_config['restic_repo'],
|
||||
'svc_keycloak': deployment_config['svc_keycloak'],
|
||||
'svc_mailcow': deployment_config['svc_mailcow'],
|
||||
'svc_wazuh': deployment_config['svc_wazuh'],
|
||||
'svc_stepca': deployment_config['svc_stepca'],
|
||||
'banner_text': deployment_config['banner_text']
|
||||
}
|
||||
REQUIRED_FIELDS = [
|
||||
"global_admin_username", "admin_ssh_public_key", "domain_name",
|
||||
"hostname", "nextcloud_port", "mailcow_port", "keycloak_port",
|
||||
"keycloak_image", "nextcloud_aio_image", "mailcow_image"
|
||||
]
|
||||
|
||||
# Save to group_vars/all.yml
|
||||
with open('group_vars/all.yml', 'w') as f:
|
||||
yaml.dump(group_vars, f, sort_keys=False, default_flow_style=False)
|
||||
def load_config():
|
||||
if not Path(CONFIG_FILE).exists():
|
||||
sys.exit(f"[!] {CONFIG_FILE} not found.")
|
||||
with open(CONFIG_FILE, "r") as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
def validate_config(cfg):
|
||||
missing = [key for key in REQUIRED_FIELDS if key not in cfg]
|
||||
if missing:
|
||||
sys.exit(f"[!] Missing required keys in {CONFIG_FILE}: {', '.join(missing)}")
|
||||
|
||||
def build_output(cfg):
|
||||
return {
|
||||
# Global User
|
||||
"default_user": cfg["global_admin_username"],
|
||||
"default_shell": "/bin/bash",
|
||||
"ssh_authorized_key": cfg["admin_ssh_public_key"],
|
||||
|
||||
# System Info
|
||||
"domain_name": cfg["domain_name"],
|
||||
"hostname": cfg["hostname"],
|
||||
"timezone": cfg.get("timezone", "UTC"),
|
||||
"dns_resolver_ip": cfg.get("dns_resolver_ip", "1.1.1.1"),
|
||||
|
||||
# Network Ports
|
||||
"nextcloud_port": cfg["nextcloud_port"],
|
||||
"mailcow_port": cfg["mailcow_port"],
|
||||
"keycloak_port": cfg["keycloak_port"],
|
||||
"stepca_port": cfg.get("stepca_port", 9000),
|
||||
"wazuh_port": cfg.get("wazuh_port", 55000),
|
||||
|
||||
# Container Images
|
||||
"nextcloud_aio_image": cfg["nextcloud_aio_image"],
|
||||
"keycloak_image": cfg["keycloak_image"],
|
||||
"mailcow_image": cfg["mailcow_image"],
|
||||
|
||||
# Paths
|
||||
"nextcloud_data_dir": cfg.get("nextcloud_data_dir", "/srv/nextcloud"),
|
||||
"mailcow_data_dir": cfg.get("mailcow_data_dir", "/opt/mailcow"),
|
||||
"backup_base_dir": cfg.get("backup_base_dir", "/srv/backups"),
|
||||
"logs_dir": cfg.get("logs_dir", "/var/log/open-cmmc"),
|
||||
|
||||
# System Accounts
|
||||
"svc_keycloak": cfg.get("svc_keycloak", "svc_keycloak"),
|
||||
"svc_mailcow": cfg.get("svc_mailcow", "svc_mailcow"),
|
||||
"svc_wazuh": cfg.get("svc_wazuh", "svc_wazuh"),
|
||||
"svc_stepca": cfg.get("svc_stepca", "svc_stepca"),
|
||||
|
||||
# Backup
|
||||
"restic_password": cfg.get("restic_password", "changeme-securely"),
|
||||
"restic_repo": cfg.get("restic_repo", "/srv/backups/restic-repo"),
|
||||
|
||||
# Mailcow
|
||||
"mailcow_hostname": cfg.get("mailcow_hostname", "mail"),
|
||||
"mailcow_fqdn": f"{cfg.get('mailcow_hostname', 'mail')}.{cfg['domain_name']}",
|
||||
"mailcow_admin_user": cfg.get("mailcow_admin_user", "admin"),
|
||||
"mailcow_admin_password": cfg.get("mailcow_admin_password", "changeme"),
|
||||
"mailcow_letsencrypt_email": cfg.get("mailcow_letsencrypt_email", "admin@localhost"),
|
||||
"mailcow_use_letsencrypt": cfg.get("mailcow_use_letsencrypt", "n"),
|
||||
|
||||
# SSO & VPN
|
||||
"tailscale_auth_key": cfg.get("tailscale_auth_key", ""),
|
||||
"keycloak_realm": cfg.get("keycloak_realm", "OpenCMMC"),
|
||||
"keycloak_admin_user": cfg.get("keycloak_admin_user", "admin"),
|
||||
"keycloak_admin_password": cfg.get("keycloak_admin_password", "changeme"),
|
||||
}
|
||||
|
||||
def main():
|
||||
config = load_config()
|
||||
validate_config(config)
|
||||
output = build_output(config)
|
||||
|
||||
Path("group_vars").mkdir(parents=True, exist_ok=True)
|
||||
with open(OUTPUT_FILE, "w") as f:
|
||||
yaml.dump(output, f, sort_keys=False, default_flow_style=False)
|
||||
|
||||
print(f"[✓] {OUTPUT_FILE} generated successfully from {CONFIG_FILE}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
Loading…
Reference in New Issue