Skip to content

Commit

Permalink
Portainer, email notifs, ldap ssp
Browse files Browse the repository at this point in the history
- Detect terraform usage, use dynamic inventory
- AWS template: use SES for emails
- Barebone, local template updates
- LDAP: self-service email reset
- Grafana: always use SSL
- Grafana: email config
- Portainer: new role
- Fix: swarm auth health check
  • Loading branch information
stelcheck committed Nov 15, 2018
1 parent bb4ae0a commit a28ed4e
Show file tree
Hide file tree
Showing 28 changed files with 498 additions and 11 deletions.
4 changes: 2 additions & 2 deletions buildconfig.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ binary:
name: "dawn"

# The current version of the binary
version: "0.12.10"
version: "0.14.0"

# (Optional) URLs to call when attempting auto-update.
# Defaults:
Expand Down Expand Up @@ -78,7 +78,7 @@ image:
name: dawn

# Current image version
version: "0.12.10"
version: "0.14.0"

# Root folder where most files will be uploaded or mounted
root_folder: /dawn
Expand Down
16 changes: 16 additions & 0 deletions docker-image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ RUN wget -q https://releases.hashicorp.com/terraform/${terraform_version}/terraf
&& unzip -q /tmp/terraform.zip \
&& rm /tmp/terraform.zip

# Ansible inventory using Terraform state
RUN wget https://raw.githubusercontent.com/nbering/terraform-inventory/master/terraform.py \
-O /etc/ansible/terraform.py \
&& chmod 755 /etc/ansible/terraform.py

# Ansible provider
ARG terraform_ansible_repo=https://github.com/nbering/terraform-provider-ansible
ARG terraform_ansible_version=v0.0.4

RUN cd /tmp \
&& export zip="terraform-provider-ansible-linux_386.zip" \
&& wget ${terraform_ansible_repo}/releases/download/${terraform_ansible_version}/${zip} \
&& unzip ${zip} \
&& mv linux_386/terraform-provider-ansible_${terraform_ansible_version} /usr/bin/terraform-provider-ansible \
&& rm ${zip}

# Install Vault
RUN wget -q https://releases.hashicorp.com/vault/${vault_version}/vault_${vault_version}_linux_amd64.zip \
-O /tmp/vault.zip \
Expand Down
12 changes: 6 additions & 6 deletions docker-image/ansible/roles/grafana/templates/grafana.ini.j2
Original file line number Diff line number Diff line change
Expand Up @@ -273,16 +273,16 @@ config_file = /etc/grafana/ldap.toml

#################################### SMTP / Emailing ##########################
[smtp]
;enabled = false
;host = localhost:25
;user =
enabled = true
host = {{ smtp_hostname }}:{{ smtp_port }}
user = {{ smtp_username }}
# If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;"""
;password =
password = {{ smtp_password }}
;cert_file =
;key_file =
;skip_verify = false
;from_address = admin@grafana.localhost
;from_name = Grafana
from_address = grafana@{{ local_domain_name }}
from_name = Grafana:{{ local_domain_name }}

[emails]
;welcome_email_on_sign_up = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ services:
traefik.port: 3000
traefik.frontend.rule: "Host:grafana.{{ local_domain_name }}"
traefik.frontend.whitelist.sourceRange: "{{ grafana_whitelist }}"
traefik.frontend.headers.SSLRedirect: "true"
traefik.backend.loadbalancer.stickiness: "true"
traefik.docker.network: traefik_net
6 changes: 6 additions & 0 deletions docker-image/ansible/roles/openldap/meta/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ dependencies:
service_port: 18080
service_ip: "{{ group_ipv4.control[0] }}"
service_whitelist: "{{ phpldapadmin_whitelist }}"
- role: traefik-expose
service_name: ldap-ssp
service_scheme: http
service_port: 28080
service_ip: "{{ group_ipv4.control[0] }}"
service_whitelist: "{{ phpldapadmin_whitelist }}"
25 changes: 25 additions & 0 deletions docker-image/ansible/roles/openldap/tasks/setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,31 @@
PHPLDAPADMIN_HTTPS: "false"
PHPLDAPADMIN_TRUST_PROXY_SSL: "true"

- name: "Start self-service password reset"
docker_container:
name: ldap-ssp
image: tiredofit/self-service-password
restart_policy: always
published_ports:
- "28080:80"
links:
- "openldap:ldap"
env:
SECRETEKEY: "all your base are belong to us"
LDAP_SERVER: "ldap://{{ ldap_server }}:{{ ldap_server_port }}"
LDAP_BINDDN: "{{ ldap_admin_user }}"
LDAP_BINDPASS: "{{ ldap_admin_password }}"
LDAP_BASE_SEARCH: "{{ ldap_dc }}"
PASSWORD_MIN_LENGTH: 8
MAIL_FROM: "ldap@{{ local_domain_name }}"
MAIL_FROM_NAME: "LDAP:{{ local_domain_name }}"
NOTIFY_ON_CHANGE: true
SMTP_HOST: "{{ smtp_hostname }}"
SMTP_PORT: "{{ smtp_port }}"
SMTP_AUTH_ON: "true"
SMTP_USER: "{{ smtp_username }}"
SMTP_PASS: "{{ smtp_password }}"

- name: "Create the different organizational units"
ldap_entry:
server_uri: "ldap://{{ ldap_server }}:{{ ldap_server_port }}/"
Expand Down
21 changes: 21 additions & 0 deletions docker-image/ansible/roles/portainer/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
portainer_version: "1.19.2"

portainer_endpoint: "portainer.{{ local_domain_name }}"
portainer_whitelist: "0.0.0.0/0"
portainer_stack: "portainer"
portainer_stack_file: "/opt/dawn/portainer.yml"

portainer_admin_username: "admin"
portainer_admin_password: "RkhGg!,n4JM.SqcTV>4r@sEM"

portainer_allow_bindmounts_users: true
portainer_allow_privileged_users: true

docker_client_key_file: /etc/ssl/certs/docker/client.key.pem
docker_client_cert_file: /etc/ssl/certs/docker/client.cert.pem
docker_client_ca_file: /etc/ssl/certs/docker/client.ca.pem

ldap_server: "{{ group_ipv4.control[0] }}"
ldap_server_port: 389
ldap_dc: "dc={{ local_domain_name.split('.') | join(',dc=') }}"
ldap_admin_user: "cn=admin,{{ ldap_dc }}"
43 changes: 43 additions & 0 deletions docker-image/ansible/roles/portainer/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
- import_tasks: server.yml
when: groups['control'][0] == inventory_hostname

- name: "Generate authentication token"
uri:
url: "https://{{ portainer_endpoint }}/api/auth"
method: POST
return_content: yes
body_format: json
body: '{ "Username":"{{ portainer_admin_username }}", "Password":"{{ portainer_admin_password }}"}'
register: auth_token

- name: "Check if endpoint is registered"
warn: false
shell: |
curl "https://{{ portainer_endpoint }}/api/endpoints" \
-XGET \
-H "Authorization: {{ (auth_token.content|from_json).jwt }}"
register: portainer_endpoints
changed_when: >
portainer_endpoints.stdout
|from_json
|selectattr("Name", "equalto", inventory_hostname)
|list
|length == 0
- name: "Register endpoint"
warn: false
shell: |
curl "https://{{ portainer_endpoint }}/api/endpoints" \
-XPOST \
-H "Authorization: {{ (auth_token.content|from_json).jwt }}" \
-F "Name={{ inventory_hostname }}" \
-F "EndpointType=1" \
-F "URL=tcp://{{ private_ipv4 + ":2376" }}" \
-F "PublicURL={{ private_ipv4 + ":2376" }}" \
-F "TLS=true" \
-F "TLSSkipVerify=false" \
-F "TLSSkipClientVerify=false" \
-F "TLSCACertFile=@{{ docker_client_ca_file }}" \
-F "TLSCertFile=@{{ docker_client_cert_file }}" \
-F "TLSKeyFile=@{{ docker_client_key_file }}"
when: portainer_endpoints.changed|bool
60 changes: 60 additions & 0 deletions docker-image/ansible/roles/portainer/tasks/server.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
- name: "Create portainer stack file"
template:
dest: "{{ portainer_stack_file }}"
src: "portainer_stack.yml.j2"
register: portainer_stack_file_status

- name: "Check if portainer is running"
shell: "docker stack ps {{ portainer_stack }}"
changed_when: portainer_running_state.rc != 0
ignore_errors: yes
register: portainer_running_state

- name: "Start portainer on the cluster"
when: >
portainer_running_state.changed|bool
or portainer_stack_file_status.changed|bool
shell: "docker stack deploy -c '{{ portainer_stack_file }}' {{ portainer_stack }}"

- name: "Check if we will need to create admin user"
uri:
url: "https://{{ portainer_endpoint }}/api/auth"
method: POST
return_content: yes
body_format: json
body: '{ "Username":"{{ portainer_admin_username }}", "Password":"{{ portainer_admin_password }}"}'
changed_when: portainer_create_user|failed
register: portainer_create_user
ignore_errors: true

- name: "Configure admin user password"
uri:
url: "https://{{ portainer_endpoint }}/api/users/admin/init"
method: POST
return_content: yes
body_format: json
body: '{ "Username":"{{ portainer_admin_username }}", "Password":"{{ portainer_admin_password }}"}'
when: portainer_create_user.changed|bool
register: portainer_user_created
retries: 10
delay: 10
until: portainer_user_created|success

- name: "Generate authentication token"
uri:
url: "https://{{ portainer_endpoint }}/api/auth"
method: POST
return_content: yes
body_format: json
body: '{ "Username":"{{ portainer_admin_username }}", "Password":"{{ portainer_admin_password }}"}'
register: auth_token

- name: "Configure portainer settings"
uri:
url: "https://{{ portainer_endpoint }}/api/settings"
method: PUT
return_content: yes
headers:
Authorization: "{{ (auth_token.content|from_json).jwt }}"
body_format: json
body: "{{ lookup('template','settings.json.j2') }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
version: '3'

volumes:
portainer_data:

networks:
prometheus:
external:
name: prometheus_net
traefik:
external:
name: traefik_net

services:
portainer:
image: portainer/portainer:{{ portainer_version }}
command: -H unix:///var/run/docker.sock
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
networks:
- prometheus
- traefik
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints:
- engine.labels.dawn.node.type == control
labels:
traefik.port: 9000
traefik.frontend.rule: "Host: {{ portainer_endpoint }}"
traefik.frontend.whitelist.sourceRange: "{{ portainer_whitelist }}"
traefik.frontend.headers.SSLRedirect: "true"
traefik.backend.loadbalancer.stickiness: "true"
traefik.docker.network: traefik_net
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"Name": "Dawn Registry",
"URL": "{{ registry_url }}:{{ registry_port }}",
"Authentication": true,
"Username": "{{ registry_username }}",
"Password": "{{ registry_password }}"
}
38 changes: 38 additions & 0 deletions docker-image/ansible/roles/portainer/templates/settings.json.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
{% if portainer_templates_url is defined %}
"TemplatesURL": "{{ portainer_templates_url }}",
{% endif %}
{% if portainer_company_logo_url is defined %}
"LogoURL": "{{ portainer_company_logo_url }}",
{% endif %}
"DisplayDonationHeader": false,
"DisplayExternalContributors": true,
"AuthenticationMethod": 2,
"LDAPSettings": {
"ReaderDN": "{{ ldap_admin_user }}",
"Password": "{{ ldap_admin_password }}",
"URL": "{{ ldap_server }}:{{ ldap_server_port }}",
"TLSConfig": {
"TLS": false,
"TLSSkipVerify": true
},
"StartTLS": false,
"SearchSettings": [
{
"BaseDN": "ou=users,{{ ldap_dc }}",
"Filter": "",
"UserNameAttribute": "uid"
}
],
"GroupSearchSettings": [
{
"GroupBaseDN": "ou=groups,{{ ldap_dc }}",
"GroupFilter": "",
"GroupAttribute": "cn"
}
],
"AutoCreateUsers": true
},
"AllowBindMountsForRegularUsers": {{ portainer_allow_bindmounts_users }},
"AllowPrivilegedModeForRegularUsers": {{ portainer_allow_privileged_users }}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ chmod -R 0640 "${DOCKER_CERT_PATH}"

# health check - if null, the received data differs from expected
if
! grep -sr null "${DOCKER_CERT_PATH}"
grep -sr null "${DOCKER_CERT_PATH}"
then
echo "!!! Certificate creation failed:"
echo "${DOCKER_CERT}"
Expand Down
6 changes: 6 additions & 0 deletions docker-image/scripts/docker_entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ fi

popd > /dev/null

if
[ -d "${PROJECT_ENVIRONMENT_FILES_PATH}/terraform" ]
then
export ANSIBLE_INVENTORY="/etc/ansible/terraform.py"
fi

# We finally downgrade the user and run the
# command. The reason for this is twofold:
#
Expand Down
2 changes: 2 additions & 0 deletions docker-image/scripts/pylib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,13 @@
# display additional information
motd_section "Web UI"
motd_section_entry "Portainer" "https://portainer.{{ local_domain_name }}/"
motd_section_entry "Kibana" "https://kibana.{{ local_domain_name }}/"
motd_section_entry "Grafana" "https://grafana.{{ local_domain_name }}/"
motd_section_entry "Prometheus" "https://prometheus.{{ local_domain_name }}"
motd_section_entry "Traefik" "https://{{ local_domain_name }}:8080"
motd_section_entry "LDAP Admin" "https://ldap-admin.{{ local_domain_name }}"
motd_section_entry "Pass. reset" "https://ldap-ssp.{{ local_domain_name }}"
motd_section_entry "Teleport" "https://teleport.{{ local_domain_name }}"
motd_section_end
Expand Down
3 changes: 1 addition & 2 deletions docker-image/templates/aws/ansible/group_vars/all
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
# do it in your inventory [all:vars] section or use --extra-vars, it is used by
# docker containers and various elements of dawn to find which machines is where
# via consul
# local_domain_name: local.dawn
# local_domain_dc: in
local_domain_dc: in
local_domain_full: "{{ local_domain_dc }}.{{ local_domain_name }}"

# Local storage is used to put your client vault certificates and vault config
Expand Down
8 changes: 8 additions & 0 deletions docker-image/templates/aws/ansible/playbook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,13 @@
- role: grafana
tags: [ 'group:monitor', 'role:grafana', 'type:monitoring' ]

# Deploy portainer
- hosts: all
become: true
gather_facts: yes
roles:
- role: portainer
tags: [ 'role:portainer' ]

# Fetch client certificates
- include: /dawn/ansible/playbooks/client_certs.yml
4 changes: 4 additions & 0 deletions docker-image/templates/aws/terraform.tfvars
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# Region
region = "us-west-1"
ses_region = "us-west-2"

# Availability zone
availability_zone = "us-west-1b"

# Domain name for the environment
domain = ""

# CIDR Block to assign to the VPC's network
cidr_blocks = {
vpc = "172.24.0.0/16"
Expand Down
Loading

0 comments on commit a28ed4e

Please sign in to comment.