finish vagrant configuration

- ignore collected assets
- setup virtualenv and environment variables
- import additional salt state modules
This commit is contained in:
Jan Dittberner 2015-10-04 23:02:04 +02:00
parent b07ab0a14b
commit 33338af352
11 changed files with 359 additions and 4 deletions

1
.gitignore vendored
View file

@ -45,3 +45,4 @@ tags
_build/
*.mo
.vagrant/
gnuviechadmin/assets/

1
Vagrantfile vendored
View file

@ -23,6 +23,7 @@ Vagrant.configure(2) do |config|
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
config.vm.network "forwarded_port", guest: 443, host: 8443
config.vm.network "forwarded_port", guest: 8000, host: 8000
# Create a private network, which allows host-only access to the machine
# using a specific IP.

View file

@ -27,7 +27,6 @@ EOF
cat >/etc/salt/grains <<EOF
roles:
- webserver
- gnuviechadmin.database
- gnuviechadmin.queues
- gnuviechadmin.webinterface

View file

@ -7,8 +7,7 @@ gnuviechadmin:
adminemail: admin@gnuviech-server.de
sitename: Gnuviech Customer Self Service
domainname: localhost
checkout: /srv/www/gnuviechadmin
virtualenv: /home/gva/.virtualenvs/gnuviechadmin
virtualenv: /home/vagrant/gva-venv
devinstance: True
minosuid: 10000
minosgid: 10000

View file

@ -0,0 +1,117 @@
# -*- coding: utf-8 -*-
#
# some internal functions are copied from salt.states.file
from Crypto.PublicKey import RSA
import os
def _check_user(user, group):
'''
Checks if the named user and group are present on the minion
'''
err = ''
if user:
uid = __salt__['file.user_to_uid'](user)
if uid == '':
err += 'User {0} is not available '.format(user)
if group:
gid = __salt__['file.group_to_gid'](group)
if gid == '':
err += 'Group {0} is not available'.format(group)
return err
def _error(ret, err_msg):
ret['result'] = False
ret['comment'] = err_msg
return ret
def _calculate_umask(mode):
mode = str(mode).lstrip('0')
if not mode:
mode = '0'
modeint = int(mode, 8)
return modeint ^ 0777
def valid_key(name, bits=2048, user=None, group=None, mode='0700'):
"""
Make sure that the given key file exists and contains a valid RSA key.
name
The name of the key file to check
bits
Minimum bits for the RSA key
user
The user to own the file, this defaults to the user salt is running as
on the minion
group
The group ownership set for the file, this defaults to the group salt
is running on the minion
mode
The permissions set on the file, this defaults to 0600
"""
mode = __salt__['config.manage_mode'](mode)
ret = {
'name': name,
'changes': {},
'result': None,
'comment': ''}
if not os.path.isfile(name) and __opts__['test']:
ret['comment'] = 'would create RSA key in file {0}'.format(name)
return ret
u_check = _check_user(user, group)
if u_check:
return _error(ret, u_check)
if not os.path.isabs(name):
return _error(
ret, 'Specified file {0} is not an absolute path'.format(name))
if os.path.isdir(name):
return _error(
ret, 'Specified target {0} is a directory'.format(name))
if os.path.exists(name):
ret, perms = __salt__['file.check_perms'](
name, ret, user, group, mode)
if __opts__['test']:
ret['comment'] = 'File {0} not updated'.format(name)
return ret
if not os.path.isfile(name):
rsa = RSA.generate(bits)
oldumask = os.umask(_calculate_umask(mode))
with open(name, 'w') as rsafile:
rsafile.write(rsa.exportKey())
os.umask(oldumask)
ret['comment'] = 'created new RSA key and saved PEM file {0}'.format(
name)
ret['changes']['created'] = name
ret['result'] = True
return ret
try:
with open(name, 'r') as rsafile:
rsa = RSA.importKey(rsafile.read())
except Exception as e:
ret['comment'] = 'error loading RSA key from file {0}: {1}'.format(
name, e)
ret['result'] = False
return ret
keysize = rsa.size() + 1
if keysize < bits:
ret['comment'] = (
'RSA key in {0} is only {1} bits, which is less than the '
'required {2} bits'.format(name, keysize, bits))
ret['result'] = False
else:
ret['comment'] = 'RSA key in file {0} is ok ({1} bits)'.format(
name, keysize)
ret['result'] = True
return ret

View file

@ -0,0 +1,61 @@
# -*- coding: utf8 -*-
'''
Manage X.509 certificate life cycle
===================================
This state is useful for managing X.509 certificates' life cycles.
Copyright (c) 2014 Jan Dittberner <jan@dittberner.info>
'''
from M2Crypto import X509
from datetime import datetime
import os
def _error(ret, err_msg):
ret['result'] = False
ret['comment'] = err_msg
return ret
def valid_certificate(
name, mindays=14, keyfile=None,
checkchain=False, trustedcerts=None):
'''
Checks whether the given certificate file is valid.
name
The name of the certificate file to check
mindays
Mark the certificate as invalid if it is valid for less then this many
days
'''
ret = {
'name': name,
'changes': {},
'result': None,
'comment': ''}
if not os.path.isfile(name):
return _error(
ret, 'certificate file {0} does not exist'.format(name))
try:
cert = X509.load_cert(name)
except Exception as e:
return _error(
ret,
'error loading certificate {0}: {1}'.format(name, e))
notafter = cert.get_not_after().get_datetime()
delta = notafter - datetime.now(notafter.tzinfo)
if delta.days < mindays:
return _error(
ret,
'certificate {0} is only valid for {1} more day(s)'.format(
name, delta.days))
# TODO: check keyfile match
# TODO: check trust chain
ret['comment'] = (
'certificate {0} is ok and still valid for {1} days'.format(
name, delta.days))
ret['result'] = True
return ret

View file

@ -0,0 +1,27 @@
server {
server_name www.{{ domainname }};
listen 443 ssl;
ssl_certificate {{ ssl_certdir }}/{{ domainname }}.crt.pem;
ssl_certificate_key {{ ssl_keydir }}/{{ domainname }}.key.pem;
if ( $host != '{{ domainname }}') {
return 301 https://{{ domainname }}$request_uri;
}
client_max_body_size 1M;
gzip on;
gzip_types text/javascript application/x-javascript text/css;
location /media {
alias /vagrant/gnuviechadmin/media;
}
location /static {
alias /vagrant/gnuviechadmin/assets;
}
location / {
proxy_pass http://localhost:8000;
}
}

View file

@ -0,0 +1,24 @@
#!/bin/sh
export DJANGO_SETTINGS_MODULE="gnuviechadmin.settings.production"
export GVA_ADMIN_NAME="Jan Dittberner"
export GVA_ADMIN_EMAIL="{{ salt['pillar.get']('gnuviechadmin:adminemail') }}"
export GVA_PGSQL_DATABASE="{{ salt['pillar.get']('gnuviechadmin-database:database') }}"
export GVA_PGSQL_USER="{{ salt['pillar.get']('gnuviechadmin-database:owner:user') }}"
export GVA_PGSQL_PASSWORD="{{ salt['pillar.get']('gnuviechadmin-database:owner:password') }}"
export GVA_PGSQL_HOSTNAME="{{ salt['pillar.get']('gnuviechadmin-database:hostname') }}"
export GVA_PGSQL_PORT={{ salt['pillar.get']('gnuviechadmin-database:port') }}
export GVA_DOMAIN_NAME="{{ salt['pillar.get']('gnuviechadmin:domainname') }}"
export GVA_SITE_NAME="{{ salt['pillar.get']('gnuviechadmin:sitename') }}"
export GVA_SITE_SECRET="{{ salt['grains.get_or_set_hash']('gnuviechadmin:SECRET_KEY', 50) }}"
export GVA_SITE_ADMINMAIL="{{ salt['pillar.get']('gnuviechadmin:adminemail') }}"
export GVA_MIN_OS_UID={{ salt['pillar.get']('gnuviechadmin:minosuid') }}
export GVA_MIN_OS_GID={{ salt['pillar.get']('gnuviechadmin:minosgid') }}
export GVA_OSUSER_PREFIX="{{ salt['pillar.get']('gnuviechadmin:osuserprefix') }}"
export GVA_OSUSER_HOME_BASEPATH="{{ salt['pillar.get']('gnuviechadmin:osuserhomedirbase') }}"
export GVA_OSUSER_DEFAULT_SHELL="{{ salt['pillar.get']('gnuviechadmin:osuserdefaultshell') }}"
export GVA_BROKER_URL="{{ broker_url }}"
export GVA_OSUSER_UPLOADSERVER="{{ salt['pillar.get']('gnuviechadmin:uploadserver') }}"
export GVA_WEBMAIL_URL="{{ salt['pillar.get']('gnuviechadmin:webmail_url') }}"
export GVA_PHPMYADMIN_URL="{{ salt['pillar.get']('gnuviechadmin:phpmyadmin_url') }}"
export GVA_PHPPGADMIN_URL="{{ salt['pillar.get']('gnuviechadmin:phppgadmin_url') }}"

View file

@ -0,0 +1,97 @@
include:
- webserver
gnuviechadmin-packages:
pkg.installed:
- names:
- libpq-dev
- libyaml-dev
- python-virtualenv
- python-dev
- python-pip
{% import "webserver/sslcert.macros.sls" as sslcert %}
{% set venv = salt['pillar.get']('gnuviechadmin:virtualenv') %}
{% set domainname = salt['pillar.get']('gnuviechadmin:domainname') %}
{{ sslcert.key_cert(domainname) }}
{{ venv }}:
file.directory:
- user: vagrant
- group: vagrant
- require:
- cmd: gnuviechadmin-venv
/home/vagrant/gvasettings.sh:
file.managed:
- user: vagrant
- group: vagrant
- mode: 0640
- source: salt://gnuviechadmin/gvasettings.sh
- template: jinja
- context:
broker_url: amqp://{{ salt['pillar.get']('gnuviechadmin-queues:owner:user') }}:{{ salt['pillar.get']('gnuviechadmin-queues:owner:password') }}@mq/{{ salt['pillar.get']('gnuviechadmin-queues:vhost') }}
gnuviechadmin-venv:
cmd.run:
- name: virtualenv {{ venv }}
- user: vagrant
- group: vagrant
- unless: test -f {{ venv }}/bin/pip
gnuviechadmin-requires:
cmd.run:
- name: {{ venv }}/bin/pip install -U -r requirements/local.txt && touch {{ venv }}/lastinstall
- user: vagrant
- group: vagrant
- cwd: /vagrant
- require:
- file: {{ venv }}
- pkg: python-dev
- pkg: libpq-dev
- unless: test -e {{ venv }}/lastinstall && test /vagrant/requirements/local.txt -ot {{ venv }}/lastinstall && test /vagrant/requirements/base.txt -ot {{ venv }}/lastinstall
gnuviechadmin-dbschema:
cmd.wait:
- name: . /home/vagrant/gvasettings.sh ; {{ venv }}/bin/python manage.py migrate --noinput
- user: vagrant
- group: vagrant
- cwd: /vagrant/gnuviechadmin
- watch:
- cmd: gnuviechadmin-requires
- file: /home/vagrant/gvasettings.sh
gnuviechadmin-locale-data-compile:
cmd.wait:
- name: . /home/vagrant/gvasettings.sh ; find /vagrant/gnuviechadmin -type d -name 'locale' | while read dir; do cd $(dirname "$dir") ; {{ venv }}/bin/python /vagrant/gnuviechadmin/manage.py compilemessages ; done
- user: vagrant
- group: vagrant
- cwd: /vagrant/gnuviechadmin
- require:
- file: /home/vagrant/gvasettings.sh
- file: {{ venv }}
/etc/nginx/sites-available/{{ domainname }}:
file.managed:
- user: root
- group: root
- mode: 0640
- source: salt://gnuviechadmin/gnuviechadmin.nginx
- template: jinja
- context:
domainname: {{ domainname }}
ssl_keydir: {{ salt['pillar.get']('nginx:sslkeydir', '/etc/nginx/ssl/private') }}
ssl_certdir: {{ salt['pillar.get']('nginx:sslcertdir', '/etc/nginx/ssl/certs') }}
- require:
- pkg: nginx
- watch_in:
- service: nginx
/etc/nginx/sites-enabled/{{ domainname }}:
file.symlink:
- target: /etc/nginx/sites-available/{{ domainname }}
- require:
- file: /etc/nginx/sites-available/{{ domainname }}
- watch_in:
- service: nginx

View file

@ -4,7 +4,7 @@ ssl_ciphers kEECDH+AESGCM:kEECDH+AES:kEECDH:EDH+AESGCM:kEDH+AES:kEDH:AESGCM:ALL:
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_dhparam {{ salt['pillar.get']('nginx:sslcertdir') }}/dhparams.pem;
ssl_dhparam {{ salt['pillar.get']('nginx:sslcertdir', '/etc/nginx/ssl/certs') }}/dhparams.pem;
# OCSP stapling
ssl_stapling on;

View file

@ -0,0 +1,29 @@
{%- macro key_cert(domain_name) %}
{% set nginx_ssl_keydir = salt['pillar.get']('nginx:sslkeydir', '/etc/nginx/ssl/private') %}
{% set nginx_ssl_certdir = salt['pillar.get']('nginx:sslcertdir', '/etc/nginx/ssl/certs') %}
{% set keyfile = nginx_ssl_keydir + '/' + domain_name + '.key.pem' %}
{% set certfile = nginx_ssl_certdir + '/' + domain_name + '.crt.pem' %}
{{ keyfile }}:
rsa_key.valid_key:
- bits: {{ salt['pillar.get']('nginx:keylength:' + domain_name, 2048) }}
- require:
- file: {{ nginx_ssl_keydir }}
- require_in:
- file: /etc/nginx/sites-available/{{ domain_name }}
- service: nginx
{{ certfile }}:
cmd.run:
- name: openssl req -new -x509 -key {{ keyfile }} -subj '/CN={{ domain_name }}' -days 730 -out {{ certfile }}
- require:
- rsa_key: {{ keyfile }}
- creates: {{ certfile }}
x509_certificate.valid_certificate:
- require:
- file: {{ nginx_ssl_certdir }}
- cmd: {{ certfile }}
- require_in:
- file: /etc/nginx/sites-available/{{ domain_name }}
- service: nginx
{% endmacro %}