Edited at

AWXをSSL対応させてみた


Ansible AWX をSSL対応にしてみた。

前提:Ansible AWXは導入済みとする事


デフォルト状態だとSSL化出来ない

・鍵を登録する事ができない

・Let's Encrypt の Webhook が使えない


鍵を登録出来るようにする

証明書が無いと始まらないので取り敢えず自己証明書でも作る

非常に雑だけどこんな感じ?

openssl genrsa 2024 > server.key

openssl req -new -key server.key > server.csr
openssl x509 -req -days 3650 -signkey server.key < server.csr > server.crt


inventory を修正し鍵の項目を作る

/root/awx/installer/inventory を手直し


/root/awx/installer/inventory

ssl_certificate=./server.crt

ssl_certificate_key=./server.key


コンテナに鍵を渡す部分のために一部ソースを修正


roles/local_docker/templates/docker-compose.yml.j2


web:
image: {{ awx_web_docker_actual_image }}
container_name: awx_web

<snip>

volumes:
- "{{ docker_compose_dir }}/SECRET_KEY:/etc/tower/SECRET_KEY"
- "{{ docker_compose_dir }}/environment.sh:/etc/tower/conf.d/environment.sh"
- "{{ docker_compose_dir }}/credentials.py:/etc/tower/conf.d/credentials.py"
これを追加 ----> - "{{ docker_compose_dir }}/nginx.conf:/etc/nginx/nginx.conf"

<snip>

{% if ssl_certificate is defined %}
- "{{ ssl_certificate +':/etc/nginx/awxweb.pem:ro' }}"
これを追加 ----> - "{{ ssl_certificate_key +':/etc/nginx/awxweb.key:ro' }}"
{% endif %}



nginx.conf.j2 を展開しないバグがあるので以下のファイルを追加


/tmp/awxcompose/nginx.conf


#user awx;

worker_processes 1;

pid /tmp/nginx.pid;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /dev/stdout main;
#X# access_log /var/log/nginx/nginx_access.log main;
error_log /var/log/nginx/nginx_error.log;

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

sendfile on;
#tcp_nopush on;
#gzip on;

upstream uwsgi {
server 127.0.0.1:8050;
}

upstream daphne {
server 127.0.0.1:8051;
}

server {
#X# listen 8052 default_server;
listen 8052;
server_name _;

# Redirect all HTTP links to the matching HTTPS page
return 301 https://$host$request_uri;
}

server {
listen 8053 ssl default_server;

ssl_certificate /etc/nginx/awxweb.pem;
ssl_certificate_key /etc/nginx/awxweb.key;

ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';

ssl_stapling on;
ssl_stapling_verify on;
ssl_session_timeout 20m;

# If you have a domain name, this is where to add it
server_name _;
keepalive_timeout 65;

# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
add_header Strict-Transport-Security max-age=15768000;
add_header Content-Security-Policy "default-src 'self'; connect-src 'self' ws: wss:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' cdn.pendo.io; img-src 'self' data:; report-uri /csp-violation/";
add_header X-Content-Security-Policy "default-src 'self'; connect-src 'self' ws: wss:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' cdn.pendo.io; img-src 'self' data:; report-uri /csp-violation/";

# Protect against click-jacking https://www.owasp.org/index.php/Testing_for_Clickjacking_(OTG-CLIENT-009)
add_header X-Frame-Options "DENY";

location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}

location /static/ {
alias /var/lib/awx/public/static/;
}

location /favicon.ico { alias /var/lib/awx/public/static/favicon.ico; }

location /websocket {
# Pass request to the upstream alias
proxy_pass http://daphne;
# Require http version 1.1 to allow for upgrade requests
proxy_http_version 1.1;
# We want proxy_buffering off for proxying to websockets.
proxy_buffering off;
# http://en.wikipedia.org/wiki/X-Forwarded-For
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# enable this if you use HTTPS:
proxy_set_header X-Forwarded-Proto https;
# pass the Host: header from the client for the sake of redirects
proxy_set_header Host $http_host;
# We've set the Host header, so we don't need Nginx to muddle
# about with redirects
proxy_redirect off;
# Depending on the request value, set the Upgrade and
# connection headers
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Connection $connection_upgrade;
}

location / {
# Add trailing / if missing
rewrite ^(.*)$http_host(.*[^/])$ $1$http_host$2/ permanent;
uwsgi_read_timeout 120s;
uwsgi_pass uwsgi;
include /etc/nginx/uwsgi_params; proxy_set_header X-Forwarded-Port 443;
}
}
}


を書き込んでおく


secret_key を一時変更


/root/awx/installer/inventory


<snip>

secret_key=awxsecret を何か適当に書き換え「""」でも可



AWX を再インストール(コンテナのリメイク)

ansible-playbook -i inventory install.yml

正常に完了したら http://該当ホスト/ へアクセスすると自動的に https:// に rewrite されていると思います。


Let's Encrypt の Webhook が使えないため standalone で証明書を取得


Let's Encrypt を取得

yum -y install certbot


certbot-auto を /usr/local/sbin にコピー

cd certbot

cp certbot-auto /usr/local/sbin


standalone で証明書取得の為一旦 docker を停止

systemctl stop docker


standalone で証明書取得をテストモードで実行(--dry-run)

certbot-auto certonly --standalone --agree-tos -m encrypy@example.com -d encrypt.example.com --dry-run

これは、1時間に5回以上のリクエストを受け付けないという rate-limit があるため出来るだけ --dry-run で確認しておいたほうが良い。

certbot-auto certonly --standalone --agree-tos -m encrypy@example.com -d encrypt.example.com --test-cert

試験的に1週間位の期間の証明書を取得することも出来る


動作確認が済んだら実際に取得

certbot-auto certonly --standalone --agree-tos -m encrypy@example.com -d encrypt.example.com

正常に取得出来ると証明書は /etc/letsencrypt/live/encrypt.example.com/fullchain.pem

秘密鍵は /etc/letsencrypt/live/encrypt.example.com/private.pem

に記録されている。

ここまで読んで「う〜ん、止めたくないし色々手間だな」とおもったら

SSLなう! を使用すれば手間はないかも知れません。

#但し、後々手間になりますけどね


inventory の 修正


/root/awx/installer/inventory

ssl_certificate=/etc/letsencrypt/live/encrypt.example.com/fullchain.pem

ssl_certificate_key=/etc/letsencrypt/live/encrypt.example.com/privkey.pem

に修正

また、secret_key を変更する


/root/awx/installer/inventory

secret_key=awxsecret を何か適当に書き換え「""」でも可


なぜ secret_key を書き換えるのかと言うと、コンテナイメージ作成の変更の有無を見ているからである。


コンテナの再ビルド


cd /root/installer/
ansible-playbook -i inventory install.yml

これでLet's Encrypt での証明書が使えるようになりました。

さぁ、SSL Labs で試験をしてみましょう。

#数分で終わります


さて、証明書の自動更新どうしよう・・・・・

Let's encrypt は無料ですが期間が3ヶ月しかありません。

3ヶ月ごとに上記作業を手作業でやるのはツライ・・・・・・

刺し身タンポポの仕事は嫌なので自動化します。


cert_update.sh

#!/bin/bash

INVENTORY=/root/awx/installer/inventory
#### date md5取得
MD5_DATE=`date | md5sum | awk '{print $1}'`
MD5_DATE_OLD=`cat MD5_DATE_OLD`

#### 証明書取得
/usr/local/sbin/certbot-auto renew

#### inventry の secret_key を更新
sed -i "s/^secret_key=$MD5_DATE_OLD/secret_key=$MD5_DATE/g" $INVENTORY
echo $MD5_DATE > MD5_DATE_OLD

#### awx再インストール
cd /root/awx/installer/
ansible-playbook -i inventory install.yml


こんな感じのスクリプトを毎月1日に実行するように cron に仕込んで起くと便利かもしれません。