diff --git a/.ansible/deploy.yaml b/.ansible/deploy.yaml new file mode 100644 index 0000000..d096137 --- /dev/null +++ b/.ansible/deploy.yaml @@ -0,0 +1,72 @@ +# ansible-playbook deploy.yaml -i inventories/dev/hosts --vault-id ~/.tokens/master_id + +- hosts: all + roles: + - common + + tasks: + + - include_role: + name: common + tasks_from: make_config_dir + + - name: 'Ensure {{ config_dir }}/config/ exists' + file: + state: directory + path: '{{ config_dir }}/config' + mode: 'u=rwx,g=rwx=,o=rwx' + + - name: 'Ensure {{ config_dir }}/db/ exists' + file: + state: directory + path: '{{ config_dir }}/db' + mode: 'u=rwx,g=rwx=,o=rwx' + + - name: 'Ensure {{ config_dir }}/secrets/ exists' + file: + state: directory + path: '{{ config_dir }}/secrets' + mode: 'u=rwx,g=rwx=,o=rwx' + + - name: 'Ensure {{ config_dir }}/certs/ exists' + file: + state: directory + path: '{{ config_dir }}/certs' + mode: 'u=rwx,g=rwx=,o=rwx' + + - name: Render public certificates + copy: + content: '{{ item.crt }}' + dest: '{{ config_dir }}/certs/{{ item.name }}.crt' + with_items: '{{ certs }}' + loop_control: + label: '{{ config_dir }}/certs/{{ item.name }}.crt' + when: certs is defined + + - name: Render private keys + copy: + content: '{{ item.key }}' + dest: '{{ config_dir }}/secrets/{{ item.name }}_key' + with_items: '{{ certs }}' + loop_control: + label: '{{ config_dir }}/secrets/{{ item.name }}_key' + when: certs is defined + + - name: 'Render password to {{ config_dir }}/secrets/password' + copy: + content: '{{ password }}' + dest: '{{ config_dir }}/secrets/password' + + - name: 'Render ca.json.j2 to {{ config_dir }}/config/ca.json' + template: + src: ca.json.j2 + dest: '{{ config_dir }}/config/ca.json' + + - name: 'Render defaults.json.j2 to {{ config_dir }}/config/defaults.json' + template: + src: defaults.json.j2 + dest: '{{ config_dir }}/config/defaults.json' + + - include_role: + name: docker + tasks_from: stack_deploy diff --git a/.ansible/inventories/production/group_vars/all/certs.yaml b/.ansible/inventories/production/group_vars/all/certs.yaml new file mode 100644 index 0000000..14f9b93 --- /dev/null +++ b/.ansible/inventories/production/group_vars/all/certs.yaml @@ -0,0 +1,104 @@ +certs: + + - name: root_ca + crt: | + -----BEGIN CERTIFICATE----- + MIIBdTCCARugAwIBAgIQKYpf/uTfoFY3J3xloeFzwTAKBggqhkjOPQQDAjAZMRcw + FQYDVQQDEw5EaWVzZWwgUm9vdCBDQTAeFw0yMDEwMTAwMzE3MjdaFw0zMDEwMDgw + MzE3MjdaMBkxFzAVBgNVBAMTDkRpZXNlbCBSb290IENBMFkwEwYHKoZIzj0CAQYI + KoZIzj0DAQcDQgAEJDu09R9dve3LplFVMJyHXQcNVK5cokEEsGitWlYFxtOMqbIM + omjxaSsO0IMCwR1ghsIgxGCl7dUCl+7aMrLXhqNFMEMwDgYDVR0PAQH/BAQDAgEG + MBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFEpSsTiAOvB1xoY8BNV9k/bs + CYaGMAoGCCqGSM49BAMCA0gAMEUCIBvBPU8DDY2mJsgtRyN4B36JkacsXRVKMBce + pC9gGIB8AiEA+e7u6fY0A8a04uehfdeUOEo4kRDSN8HhRgyyvsqHd1w= + -----END CERTIFICATE----- + key: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 65656332376232313336636265336130353034633338633436393466383065653863363236386230 + 3463383031333732326161343964303637363938346265310a666339653762646333646436633466 + 63383334623564393464663338613232656335656265663732373832356566346636656135393631 + 3832623561656537300a623663316661363037643737366138643266613337333131326363616330 + 33353363333964323236353230353964316662373263626336393431613835316463396161323862 + 63366433363263643537343935613464396134623866326538313239663433343865666262393562 + 33623635303163323433396561323630633239613137656130623532363038613031653939663936 + 33643761346334396362363265363233376233366165383161643861626261353461643863333332 + 62383062366136343539656361373732353030336639303333663934623731376537363933666532 + 33376364323661353262633938373138376261353264633461653435356535646261356136383331 + 30376633366637333463333533613362653461626164663662646164366134353830653533353964 + 34633235303837353932353838616439333338353539386664303461356262343865633266393638 + 31653630363830653739636165663739336262653533336462333132333037373835383237653132 + 66323462653731613137353730643037623932353232653938356239386535303930356536393836 + 33323563346439353664613832306466653034336266376136656535366234363136653265666666 + 36353862643538663761616538306530373765343832643661666164313432316133316561383166 + 64633836343963343535613037646163663639333837663239616233613966353537393539353132 + 65336430393466333563616537663835633665653061326562653063653866643861323561313863 + 32383264633739393535333362303030633433333465343664613265643461363032653135643662 + 63316234326332663035 + + - name: intermediate_ca + crt: | + -----BEGIN CERTIFICATE----- + MIIBnTCCAUSgAwIBAgIQRX7JxLiPr5BPenqfaWxXATAKBggqhkjOPQQDAjAZMRcw + FQYDVQQDEw5EaWVzZWwgUm9vdCBDQTAeFw0yMDEwMTAwMzE3MjdaFw0zMDEwMDgw + MzE3MjdaMCExHzAdBgNVBAMTFkRpZXNlbCBJbnRlcm1lZGlhdGUgQ0EwWTATBgcq + hkjOPQIBBggqhkjOPQMBBwNCAAR5gKfLlM94iKH4rMeX6aB8NrBh14UQXmD6tcME + ukcKtB3cOy9ya2ymjxCk0np/BCfQ4hzRrJectM1IgJWynPbCo2YwZDAOBgNVHQ8B + Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQURDmokHjxn8Xd + SqCU37HD3vJEC18wHwYDVR0jBBgwFoAUSlKxOIA68HXGhjwE1X2T9uwJhoYwCgYI + KoZIzj0EAwIDRwAwRAIgLRIWITSgQRM/avkH+3hqQVdpBiJglfqsD31Tu4low2IC + IBch9ASGXta7GSvq+xxqBm6vMv7I9Etzdw3xO+ysWVDi + -----END CERTIFICATE----- + key: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 38613766656235343962653932643366636161346633316261386665333665386665323839386133 + 6164653032353035393165393432383136613765306161610a353932353237373066336566653962 + 32363033323161643865653231643862366435646461616535326139326231613865643038623764 + 3435393733646661330a613063383637633938363434643839373138333134656130366562623433 + 62373539373061643533373737623436633665366133666634306130333735323136623232636431 + 32333535376533633766633162363932616563373131636330653334393938303233336363316566 + 36633530383364373432383531323232316361376234363234316337306330303432343537303732 + 37653536396161616131363732656532613733323932363332373064623366646165353039626135 + 30323732613038353535316431623661376434303939663239666163303238396431336238373038 + 63663466373262636463343362636530343138323738643335373739323536336665326432356564 + 39643737613333623262313866393432626565353665613832343234623366646464323665643464 + 64313436623661313664636563373361653336363939393335326636323333393537633134326232 + 30663636343234643532386339373861366534363533386433633562313662353635343336386265 + 34376137363532616334333230396562323361373035653133306461393632616435353465386336 + 66646261316230623166386138653231396639353163326463633037363438353238616137373635 + 65313035336439383130396137663133386637353731623262366363653436653861353036656439 + 32393165336239363063626632353964356362326233646231626534326165323636303331653231 + 38396236616361633236333733386131373635623036353865366462333437633965626631346433 + 32393965373332336437666434383837393331316566666163383339343831316330393034396363 + 64383765363531393938 + + - name: pfsense_intermediate_ca + crt: | + -----BEGIN CERTIFICATE----- + MIIBnzCCAUagAwIBAgIRALe+7jp1W5LCKWnYEdSKvsgwCgYIKoZIzj0EAwIwGTEX + MBUGA1UEAxMORGllc2VsIFJvb3QgQ0EwHhcNMjAxMDE4MjE0NzQyWhcNMzAxMDE2 + MjE0NzQyWjAiMSAwHgYDVQQDExdwZlNlbnNlIEludGVybWVkaWF0ZSBDQTBZMBMG + ByqGSM49AgEGCCqGSM49AwEHA0IABKWWSA95AVPasD9M6l0rKqx2HZL1+hFsCr+M + C2qXzvxhaFt0B/ht11N2iIwS4IlU6LPSlYvxcH+u8YgfAkL9AcKjZjBkMA4GA1Ud + DwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQplup/8/AG + YKDoC7foLztPTBpABTAfBgNVHSMEGDAWgBRKUrE4gDrwdcaGPATVfZP27AmGhjAK + BggqhkjOPQQDAgNHADBEAiBcZOhKsxS1x/FT62OBaNUB6+vinwaqbo88sbUh6l3N + OwIgBA9+YcZjYAT3gSlO1W8mHMgu+ImhtjWvpYkttDvg47Q= + -----END CERTIFICATE----- + key: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 39636638636433346333613061636138313632633332663437363231313632626133613135626462 + 3462636362343464666632306130303236333063663530330a316433653466326430646432383034 + 63346535386139336366623235386166623137666232646165616130333463353537363864613861 + 6461366635346634340a613034353135383437646464353633643761363965346666613336623731 + 36643039663038626462313035396262623435326561646434656331663766653034613962383937 + 37653363366164363831376461623461363031373335353538326536393430613035313435393735 + 31613030343161616230383235326533353633326233623266306365383864363937656630336363 + 63633236316431653665356463613535306430376563366361303936643537666265323137323936 + 63376435666436376161386632323538623535313031613065313862323464383036306330373065 + 64663164323637373530313334353238346130323837616533383436353538353535626236343165 + 64343430636636663061613038613033356162356539333266333931623835323761333765396136 + 35323732626638323634316139323965633362333838623034653365336635323566666336653363 + 32323865306364383737396163663138613863386565386534316261326665626133656230663866 + 38323961363136376437646435316563343530623539323361373336336436653238376431643761 + 63633833373635663736646664646132656263356430636465316233623662626162613130303331 + 34333562393732626231 diff --git a/.ansible/inventories/production/group_vars/all/config.yaml b/.ansible/inventories/production/group_vars/all/config.yaml new file mode 100644 index 0000000..c6435b7 --- /dev/null +++ b/.ansible/inventories/production/group_vars/all/config.yaml @@ -0,0 +1,20 @@ +env: prod +domain: ca.diesel.net + +email: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 32623238373030646537663966313164333738656536616631616239353531643563653665356662 + 3137343464666534376663343733616234653366623662370a663730663431346434306236333439 + 62303163333939396137386530623661636365386661653736626164653835616165373566653163 + 3735383061643037390a343731373762313638653861323762633662373238303332383861383432 + 36343838633735343437316666346437346136323862653935313133643439663230 + +fingerprint: c4dfdfdece152139fe58280eebaa142ef25b0a19f0984ca5e5338d0d8522f7d8 +password: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 64386334383831346436646566323666626165323336643161646234323066323031646165343934 + 3030336331323863376537383962356465656234343239650a356331313963326439383432303633 + 36363039623238653231616363343537363665666631346238383730323434376563356636363936 + 3662643566353766630a323833386537613334396231323633626638623731396262336530316562 + 31363438646232336637656561316137666136303164663830333036626161623066336366373034 + 3136303837613537346664306234633463616164343866646636 diff --git a/.ansible/inventories/production/hosts b/.ansible/inventories/production/hosts new file mode 100644 index 0000000..0b948d6 --- /dev/null +++ b/.ansible/inventories/production/hosts @@ -0,0 +1,8 @@ +all: + children: + tools: + hosts: + ca.diesel.net + vars: + ansible_user: automation + ansible_python_interpreter: /usr/bin/python3 diff --git a/.ansible/roles/requirements.yaml b/.ansible/roles/requirements.yaml new file mode 100644 index 0000000..6b0b3b6 --- /dev/null +++ b/.ansible/roles/requirements.yaml @@ -0,0 +1,9 @@ +- name: common + scm: git + src: "git@github.com:Diesel-Net/ansible-role-common.git" + version: 1.0.0 + +- name: docker + scm: git + src: "git@github.com:Diesel-Net/ansible-role-docker.git" + version: 1.2.1 diff --git a/.ansible/templates/ca.json.j2 b/.ansible/templates/ca.json.j2 new file mode 100644 index 0000000..f248af2 --- /dev/null +++ b/.ansible/templates/ca.json.j2 @@ -0,0 +1,53 @@ +{ + "root": "/home/step/certs/root_ca.crt", + "federatedRoots": [], + "crt": "/home/step/certs/intermediate_ca.crt", + "key": "/home/step/secrets/intermediate_ca_key", + "address": ":443", + "dnsNames": [ + "{{ domain }}" + ], + "logger": { + "format": "text" + }, + "db": { + "type": "badger", + "dataSource": "/home/step/db", + "badgerFileLoadingMode": "" + }, + "authority": { + "provisioners": [ + { + "type": "JWK", + "name": "{{ email }}", + "key": { + "use": "sig", + "kty": "EC", + "kid": "6_aPqC-fcucfqCIfx99VKk5UovfqzExjrfq_qeIroZQ", + "crv": "P-256", + "alg": "ES256", + "x": "RkKwdvTXVEzWxru6BaFm5-JcW12WxEQ2sq2C9a74qcM", + "y": "gJ24sFSei_OupNX2D9t2Sqa7GNYEILjXWaQTLWOkUG4" + }, + "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjEwMDAwMCwicDJzIjoiZnQyY3laaDZBUHdwXy1QTlIyTm5NdyJ9.ymIisjEu0EZBsDege5jm_tRJZDNaKj3VS2Xxde3zF35TQHShWpZkqg.x5eGGZf1kzqow05B.dac4nesqDgVUy9u8Fh7zpTGv9dmPjo9tpZ_amHIBSpxVLyGK5C3sCQsEFzac3tqwRk5yV9qYjAo5xYJCqusn3KHbC4TJ5BJEQnNpfCwj4oPyMAdXh-i1RRKonJIx2dWVVC8aKv-sxyQSr3uaPp8KsoWsbbzyctZpHO6J9IcgrhbUvt6oN1zl8971Dk-PNd1KU9PZ_TdK0-79AeICCx6VqRG5PS4MdCh34b1avEM-SEYkVRA1ibJ5Jh6ZxNhIKC0WpUn5x2Pz7vT3b14OzPx-JG-gW_mz4DJcH17bgfrfsR9omNr2PTHazlfHwl_ZxEDYWeHP6IYOqnUGEiSXcfc.Zvacyx5awaEsR7tSp0Z1qA" + }, + { + "type": "ACME", + "name": "acme", + "claims": { + "maxTLSCertDuration": "2160h", + "defaultTLSCertDuration": "2160h" + } + } + ] + }, + "tls": { + "cipherSuites": [ + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + ], + "minVersion": 1.2, + "maxVersion": 1.2, + "renegotiation": false + } +} diff --git a/.ansible/templates/defaults.json.j2 b/.ansible/templates/defaults.json.j2 new file mode 100644 index 0000000..c896b84 --- /dev/null +++ b/.ansible/templates/defaults.json.j2 @@ -0,0 +1,6 @@ +{ + "ca-url": "https://{{ domain }}", + "ca-config": "/home/step/config/ca.json", + "fingerprint": "c4dfdfdece152139fe58280eebaa142ef25b0a19f0984ca5e5338d0d8522f7d8", + "root": "/home/step/certs/root_ca.crt" +} diff --git a/.ansible/templates/docker-compose.yaml.j2 b/.ansible/templates/docker-compose.yaml.j2 new file mode 100644 index 0000000..1478724 --- /dev/null +++ b/.ansible/templates/docker-compose.yaml.j2 @@ -0,0 +1,23 @@ +# docker-compose.yaml + +version: '3.8' +services: + + server: + image: smallstep/step-ca:0.15.4 + volumes: + - /etc/localtime:/etc/localtime + - {{ ssl_cert_dir }}/:/etc/ssl/certs/ + - {{ config_dir }}/:/home/step/ + networks: + - {{ docker_network }} + deploy: + labels: + - traefik.enable=true + - traefik.tcp.services.{{ git_repository }}.loadbalancer.server.port=443 + - traefik.tcp.routers.{{ git_repository }}.rule=HostSNI(`{{ domain }}`) + - traefik.tcp.routers.{{ git_repository }}.tls.passthrough=true +networks: + {{ docker_network }}: + external: + name: {{ docker_network }} diff --git a/.drone.yaml b/.drone.yaml new file mode 100644 index 0000000..fecdaa1 --- /dev/null +++ b/.drone.yaml @@ -0,0 +1,29 @@ +--- +kind: pipeline +type: docker +name: Install Step CA Server + +clone: + depth: 1 + +steps: + + - name: deploy + image: plugins/ansible:3 + environment: + ANSIBLE_CONFIG: .ansible/ansible.cfg + settings: + galaxy: .ansible/roles/requirements.yaml + inventory: .ansible/inventories/production/hosts + playbook: .ansible/deploy.yaml + private_key: + from_secret: ansible_private_key + vault_password: + from_secret: ansible_vault_password + +trigger: + branch: + - stable + event: + - push +... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ddcd25a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.ansible/roles/common +.ansible/roles/docker diff --git a/README.md b/README.md index e896747..c075d5d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ -# acme-ca-ansible -Automated deployments of a Private (internal) ACME-based Certificate Authority +# acme-ca +Automated deployments of a Private (internal) ACME-based Certificate Authority. Using Step-CA. + +## Dependencies +- Ansible 2.11+ + +## Installing Dependencies +```bash +ansible-galaxy install -r .ansible/roles/requirements.yaml -p .ansible/roles --force +``` + +## Deploy +Right now each environment is defined as an independent Virtual Machine (single-node swarm leaders) +```bash +ansible-playbook .ansible/deploy.yaml -i .ansible/inventories/production/hosts --vault-id ~/.tokens/master_id +```