diff --git a/vagrant/Puppetfile b/vagrant/Puppetfile new file mode 100644 index 0000000..d09d55b --- /dev/null +++ b/vagrant/Puppetfile @@ -0,0 +1,24 @@ +#!/usr/bin/env ruby +#^syntax detection + +forge "https://forgeapi.puppetlabs.com" + +mod 'puppetlabs-stdlib' +mod 'puppetfinland-easy_ipa', + :git => 'https://github.com/Puppet-Finland/puppet-ipa.git', + :commit => '67874ab7f40e4643b77adfd4155f9eb494776bc8' +mod 'puppetlabs-mysql' +mod 'puppetlabs-java' +mod 'puppetlabs-java_ks' +mod 'puppet-archive' +mod 'camptocamp-systemd' +mod 'puppetlabs-concat' +mod 'puppetlabs-apt' +mod 'puppetlabs-postgresql' +mod 'puppetlabs-cron_core' +mod 'puppetlabs-inifile' +mod 'puppetlabs-k5login_core' +mod 'puppetlabs-resource_api' +mod 'puppetlabs-translate' +mod 'puppetlabs-puppetserver_gem' +mod 'puppetlabs-haproxy' diff --git a/vagrant/Vagrantfile b/vagrant/Vagrantfile new file mode 100644 index 0000000..b34252b --- /dev/null +++ b/vagrant/Vagrantfile @@ -0,0 +1,107 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + config.hostmanager.enabled = true + config.hostmanager.manage_host = true + config.hostmanager.manage_guest = true + config.hostmanager.ignore_private_ip = false + config.hostmanager.include_offline = false + + config.vm.define "db" do |box| + box.vm.box = "centos/7" + box.vm.hostname = 'db.local' + box.vm.synced_folder "..", "/vagrant", type: "virtualbox" + box.hostmanager.manage_guest = true + box.hostmanager.aliases = %w(db) + box.vm.network "private_network", ip: "192.168.168.254" + box.vm.provider 'virtualbox' do |vb| + vb.linked_clone = true + vb.gui = false + vb.memory = 1024 + vb.customize ["modifyvm", :id, "--ioapic", "on"] + vb.customize ["modifyvm", :id, "--hpet", "on"] + vb.customize ["modifyvm", :id, "--audio", "none"] + end + box.vm.provision "shell" do |s| + s.path = "install_agent.sh" + end + box.vm.provision "shell" do |s| + s.path = "run_puppet.sh" + s.args = ["-b", "/vagrant", "-m", "prepare.pp db.pp" ] + end + end + + config.vm.define "master" do |box| + box.vm.box = "centos/7" + box.vm.hostname = 'master.local' + box.vm.synced_folder "..", "/vagrant", type: "virtualbox" + box.hostmanager.manage_guest = true + box.hostmanager.aliases = %w(master) + box.vm.network "private_network", ip: "192.168.168.253" + box.vm.provider 'virtualbox' do |vb| + vb.linked_clone = true + vb.gui = false + vb.memory = 1024 + vb.customize ["modifyvm", :id, "--ioapic", "on"] + vb.customize ["modifyvm", :id, "--hpet", "on"] + vb.customize ["modifyvm", :id, "--audio", "none"] + end + box.vm.provision "shell" do |s| + s.path = "install_agent.sh" + end + box.vm.provision "shell" do |s| + s.path = "run_puppet.sh" + s.args = ["-b", "/vagrant", "-m", "prepare.pp master.pp"] + end + end + + config.vm.define "slave" do |box| + box.vm.box = "centos/7" + box.vm.hostname = 'slave.local' + box.vm.synced_folder "..", "/vagrant", type: "virtualbox" + box.hostmanager.manage_guest = true + box.hostmanager.aliases = %w(slave) + box.vm.network "private_network", ip: "192.168.168.252" + box.vm.provider 'virtualbox' do |vb| + vb.linked_clone = true + vb.gui = false + vb.memory = 1024 + vb.customize ["modifyvm", :id, "--ioapic", "on"] + vb.customize ["modifyvm", :id, "--hpet", "on"] + vb.customize ["modifyvm", :id, "--audio", "none"] + end + box.vm.provision "shell" do |s| + s.path = "install_agent.sh" + end + box.vm.provision "shell" do |s| + s.path = "run_puppet.sh" + s.args = ["-b", "/vagrant", "-m", "prepare.pp slave.pp"] + end + end + + config.vm.define "lb" do |box| + box.vm.box = "centos/7" + box.vm.hostname = 'lb.local' + box.vm.synced_folder "..", "/vagrant", type: "virtualbox" + box.hostmanager.manage_guest = true + box.hostmanager.aliases = %w(lb) + box.vm.network "private_network", ip: "192.168.168.251" + box.vm.provider 'virtualbox' do |vb| + vb.linked_clone = true + vb.gui = false + vb.memory = 1024 + vb.customize ["modifyvm", :id, "--ioapic", "on"] + vb.customize ["modifyvm", :id, "--hpet", "on"] + vb.customize ["modifyvm", :id, "--audio", "none"] + end + box.vm.provision "shell" do |s| + s.path = "install_agent.sh" + end + box.vm.provision "shell" do |s| + s.path = "run_puppet.sh" + s.args = ["-b", "/vagrant", "-m", "prepare.pp lb.pp"] + end + end +end + diff --git a/vagrant/db.pp b/vagrant/db.pp new file mode 100644 index 0000000..b9fb0fa --- /dev/null +++ b/vagrant/db.pp @@ -0,0 +1,36 @@ +class { '::postgresql::globals': + manage_package_repo => $manage_package_repo, + version => $postgresql_version, +} + +class { '::postgresql::server': + listen_addresses => $postgresql_listen_address, + require => Class['::postgresql::globals'] +} + +::postgresql::server::role { $db_username: + password_hash => postgresql_password($db_username, $db_password), + connection_limit => $db_connection_limit, + require => Class['::postgresql::server'] +} + +::postgresql::server::database_grant { "Grant all to ${db_username}": + privilege => 'ALL', + db => $db_database, + role => $db_username, +} + +::postgresql::server::db { $db_database: + user => $db_username, + password => postgresql_password($db_username, $db_password), +} + +postgresql::server::pg_hba_rule { 'Allow Keycloak instances network access to the database': + description => 'Open up PostgreSQL for access from 192.168.168.0/24', + type => 'host', + database => $db_username, + user => $db_password, + address => '192.168.168.0/24', + auth_method => 'md5', + require => Class['::postgresql::server'] +} diff --git a/vagrant/install_agent.sh b/vagrant/install_agent.sh new file mode 100755 index 0000000..19b70e9 --- /dev/null +++ b/vagrant/install_agent.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +# Exit on any error +set -e + +CWD=`pwd` + +detect_osfamily() { + if [ -f /etc/redhat-release ]; then + OSFAMILY='redhat' + RELEASE=$(cat /etc/redhat-release) + if [ "`echo $RELEASE | grep -E 7\.[0-9]+`" ]; then + RHEL_VERSION="7" + else + echo "Unsupported Redhat/Centos version. Supported versions are 7.x" + exit 1 + fi + elif [ "`lsb_release -d | grep -E '(Ubuntu|Debian)'`" ]; then + OSFAMILY='debian' + DESCR="$(lsb_release -d | awk '{ print $2}')" + if [ `echo $DESCR|grep Ubuntu` ]; then + UBUNTU_VERSION="$(lsb_release -c | awk '{ print $2}')" + elif [ `echo $DESCR|grep Debian` ]; then + DEBIAN_VERSION="$(lsb_release -c | awk '{ print $2}')" + else + echo "Unsupported Debian family operating system. Supported are Debian and Ubuntu" + exit 1 + fi + else + echo "ERROR: unsupported osfamily. Supported are Debian and RedHat" + exit 1 + fi +} + +setup_puppet() { + if [ -x /opt/puppetlabs/bin/puppet ]; then + true + else + if [ $RHEL_VERSION ]; then + RELEASE_URL="https://yum.puppetlabs.com/puppet6/puppet6-release-el-${RHEL_VERSION}.noarch.rpm" + rpm -hiv "${RELEASE_URL}" || (c=$?; echo "Failed to install ${RELEASE_URL}"; (exit $c)) + yum -y install puppet-agent || (c=$?; echo "Failed to install puppet agent"; (exit $c)) + if systemctl list-unit-files --type=service | grep firewalld; then + systemctl stop firewalld + systemctl disable firewalld + systemctl mask firewalld + fi + else + if [ $UBUNTU_VERSION ]; then + APT_URL="https://apt.puppetlabs.com/puppet6-release-${UBUNTU_VERSION}.deb" + fi + if [ $DEBIAN_VERSION ]; then + APT_URL="https://apt.puppetlabs.com/puppet6-release-${DEBIAN_VERSION}.deb" + fi + # https://serverfault.com/questions/500764/dpkg-reconfigure-unable-to-re-open-stdin-no-file-or-directory + export DEBIAN_FRONTEND=noninteractive + FILE="$(mktemp -d)/puppet-release.db" + wget "${APT_URL}" -qO $FILE || (c=$?; echo "Failed to retrieve ${APT_URL}"; (exit $c)) + dpkg --install $FILE; rm $FILE; apt-get update || (c=$?; echo "Failed to install from ${FILE}"; (exit $c)) + apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y install puppet-agent || (c=$?; echo "Failed to install puppet agent"; (exit $c)) + fi + fi +} + +# Main program +detect_osfamily +setup_puppet + +cd $CWD diff --git a/vagrant/lb.pp b/vagrant/lb.pp new file mode 100644 index 0000000..3be769c --- /dev/null +++ b/vagrant/lb.pp @@ -0,0 +1,38 @@ +notify { 'Installing Load Balancer': } + +include ::haproxy + +haproxy::listen { 'kc': + collect_exported => false, + ipaddress => $facts['networking']['interfaces']['eth1']['ip'], + mode => 'http', + ports => '80', + options => { + 'option' => [ + 'tcplog', + 'forwardfor', + 'http-keep-alive' + ], + 'balance' => 'roundrobin', + 'cookie' => 'SRVNAME insert', + 'http-request' => 'set-header X-Forwarded-Port %[dst_port]', + }, +} + +haproxy::balancermember { 'master': + listening_service => 'kc', + server_names => 'master.local', + ipaddresses => '192.168.168.253', + ports => '8080', + options => 'cookie DC check', +} + +haproxy::balancermember { 'slave': + listening_service => 'kc', + server_names => 'slave.local', + ipaddresses => '192.168.168.252', + ports => '8080', + options => 'cookie HC check', +} + + diff --git a/vagrant/master.pp b/vagrant/master.pp new file mode 100644 index 0000000..0a35ad4 --- /dev/null +++ b/vagrant/master.pp @@ -0,0 +1,50 @@ +notify { 'Installing Master': } + +class { '::keycloak': + operating_mode => 'domain', + role => 'master', + management_bind_address => '192.168.168.253', + enable_jdbc_ping => true, + wildfly_user => $keycloak_wildfly_user, + wildfly_user_password => $keycloak_wildfly_user_password, + manage_install => true, + manage_datasource => false, + version => $keycloak_version, + datasource_driver => 'postgresql', + datasource_host => $keycloak_datasource_host, + datasource_port => 5432, + datasource_dbname => $keycloak_datasource_dbname, + datasource_username => $keycloak_datasource_username, + datasource_password => $keycloak_datasource_password, + admin_user => $keycloak_admin_user, + admin_user_password => $keycloak_admin_user_password, + service_bind_address => '0.0.0.0', + proxy_https => false, +} + +keycloak_realm { 'TEST.NET': + ensure => 'present', + display_name => 'TEST.NET', + display_name_html => 'TEST.NET', + login_with_email_allowed => false, + remember_me => false, + events_enabled => true, + admin_events_enabled => true, + admin_events_details_enabled => true, +} + +keycloak_client { 'example.com': + ensure => 'present', + realm => 'TEST.NET', + standard_flow_enabled => true, + protocol => 'saml', + full_scope_allowed => true, + service_accounts_enabled => false, + base_url => 'https://example.com/', + redirect_uris => [ + 'https://example.com/', + 'https://example.com/*', + ], + require => Keycloak_realm['TEST.NET'], +} + diff --git a/vagrant/prepare.pp b/vagrant/prepare.pp new file mode 100644 index 0000000..2c6d655 --- /dev/null +++ b/vagrant/prepare.pp @@ -0,0 +1,28 @@ +notify { 'Preparing for setup': } + +$tools = [ 'tcpdump', 'strace', 'nmap', 'screen', 'net-tools' ] + +package { $tools: + ensure => 'installed', +} + +package { 'r10k': + ensure => 'present', + provider => 'puppet_gem', +} + +package { 'git': + ensure => 'latest', +} + +exec { 'Update modules': + logoutput => true, + command => "r10k puppetfile install --puppetfile ${::basedir}/vagrant/Puppetfile --verbose --moduledir /etc/puppetlabs/code/environments/production/modules", # lint:ignore:140chars + timeout => 600, + path => ['/bin','/usr/bin','/opt/puppetlabs/bin','/opt/puppetlabs/puppet/bin'], +} + +file { '/etc/puppetlabs/code/environments/production/modules/keycloak': + ensure => 'link', + target => $::basedir, +} diff --git a/vagrant/run_puppet.sh b/vagrant/run_puppet.sh new file mode 100755 index 0000000..ea6f366 --- /dev/null +++ b/vagrant/run_puppet.sh @@ -0,0 +1,72 @@ +#!/bin/sh + +# Exit on any error +set -e + +# Preparations required prior to "puppet apply". + +usage() { + echo + echo "Usage: run_puppet.sh -b basedir" + echo + echo "Options:" + echo " -b Base directory for dependency Puppet modules installed by" + echo " librarian-puppet." + echo " -m Puppet manifests to run. Put them in the provision folder" + echo " -d Turn on debugging" + exit 1 +} + +# Parse the options + +# We are run without parameters -> usage +if [ "$1" = "" ]; then + usage +fi + +while getopts "b:m:h:d:" options; do + case $options in + b ) BASEDIR=$OPTARG;; + m ) MANIFESTS=$OPTARG;; + d ) DEBUG=$OPTARG;; + h ) usage;; + \? ) usage;; + * ) usage;; + esac +done + +CWD=`pwd` + +# Configure with "puppet apply" +if [ "$DEBUG" == "true" ]; then + PUPPET_APPLY="/opt/puppetlabs/bin/puppet apply --verbose --debug --trace --summarize" +else + PUPPET_APPLY="/opt/puppetlabs/bin/puppet apply" +fi + +# Pass variables to Puppet manifests via environment variables +export FACTER_profile='/etc/profile.d/myprofile.sh' +export FACTER_basedir="$BASEDIR" +export FACTER_keycloak_version='10.0.1' +export FACTER_keycloak_datasource_host='db.local' +export FACTER_keycloak_datasource_dbname='keycloak' +export FACTER_keycloak_datasource_username='keycloak' +export FACTER_keycloak_datasource_password='keycloak' +export FACTER_keycloak_admin_user='admin' +export FACTER_keycloak_admin_user_password='changeme' +export FACTER_keycloak_wildfly_user='wildfly' +export FACTER_keycloak_wildfly_user_password='wildfly' +export FACTER_manage_package_repo='false' +export FACTER_postgresql_version='9.6' +export FACTER_postgresql_manage_package_repo='true' +export FACTER_postgresql_listen_address='*' +export FACTER_db_username='keycloak' +export FACTER_db_password='keycloak' +export FACTER_db_database='keycloak' +export FACTER_db_connection_limit='300' + +for manifest in $MANIFESTS; do + $PUPPET_APPLY /vagrant/vagrant/$manifest +done + +cd $CWD diff --git a/vagrant/slave.pp b/vagrant/slave.pp new file mode 100644 index 0000000..0f876bc --- /dev/null +++ b/vagrant/slave.pp @@ -0,0 +1,25 @@ +notify { 'Installing Slave': } + +class { '::keycloak': + operating_mode => 'domain', + role => 'slave', + enable_jdbc_ping => true, + management_bind_address => '192.168.168.252', + wildfly_user => $keycloak_wildfly_user, + wildfly_user_password => $keycloak_wildfly_user_password, + master_address => '192.168.168.253', + manage_install => true, + manage_datasource => false, + version => $keycloak_version, + datasource_driver => 'postgresql', + datasource_host => $keycloak_datasource_host, + datasource_port => 5432, + datasource_dbname => $keycloak_datasource_dbname, + datasource_username => $keycloak_datasource_username, + datasource_password => $keycloak_datasource_password, + admin_user => $keycloak_admin_user, + admin_user_password => $keycloak_admin_user_password, + service_bind_address => '0.0.0.0', + proxy_https => false, +} +