1
1
Fork 0
mirror of https://gitlab.archlinux.org/archlinux/infrastructure.git synced 2024-05-07 17:26:04 +02:00

Merge wip-keyclaok into master

This commit is contained in:
Frederik Schwan 2020-04-30 14:30:35 +02:00
parent a9a6e58c07
commit f42fd92b83
No known key found for this signature in database
GPG Key ID: 9D4C5AA15426DA0A
22 changed files with 1676 additions and 50 deletions

View File

@ -9,6 +9,7 @@ It also contains git submodules so you have to run `git submodule update --init
Install these packages:
- terraform
- terraform-provider-keycloak
### Instructions
@ -58,13 +59,24 @@ This will take some time after which a new snapshot will have been created on th
#### Note about terraform
We use terraform to provision a part of the infrastructure on hcloud.
We use terraform in two ways:
1) To provision a part of the infrastructure on hcloud (and possibly other service providers in the future)
2) To declaratively configure applications
For both of these, we have set up a separate terraform script. The reason for that is that sadly terraform can't have
providers depend on other providers so we can't declaratively state that we want to configure software on a server which
itself needs to be provisioned first. Therefore, we use a two-stage process. Generally speaking, scenario 1) is configured in
`tf-stage1` and 2) is in `tf-stage2`. Maybe in the future, we can just have a single terraform script for everything
but for the time being, this is what we're stuck with.
The very first time you run terraform on your system, you'll have to init it:
terraform init -backend-config="conn_str=postgres://terraform:$(misc/get_key.py group_vars/all/vault_terraform.yml vault_terraform_db_password)@state.archlinux.org"
terraform init -backend-config="conn_str=postgres://terraform:$(../misc/get_key.py group_vars/all/vault_terraform.yml vault_terraform_db_password)@state.archlinux.org"
After making changes to the infrastructure in `archlinux.fg`, run
After making changes to the infrastructure in `tf-stage1/archlinux.fg`, run
cd tf-stage1
terraform plan
This will show you planned changes between the current infrastructure and the desired infrastructure.
@ -74,6 +86,9 @@ You can then run
to actually apply your changes.
The same applies to changed application configuration in which case you'd run
it inside of `tf-stage2` instead of `tf-stage1`.
We store terraform state on a special server that is the only hcloud server NOT
managed by terraform so that we do not run into a chicken-egg problem. The
state server is assumed to just exist so in an unlikely case where we have to
@ -193,10 +208,24 @@ The following steps should be used to update our managed servers:
#### Services:
- quassel core
## homedir.archlinux.org
### homedir.archlinux.org
#### Services:
- ~/user/ webhost
### accounts.archlinux.org
This server is /special/. It runs keycloak and is central to our unified Arch Linux account management world.
It has an Ansible playbook for the keycloak service but that only installs the package and starts it but it's configured via a secondary Terraform file only for keycloak `keycloak.tf`.
The reason for doing it this way is that Terraform support for Keycloak is much superior and it's declarative too which is great for making sure that no old config remains in the case of config changes.
So to set up this server from scratch, run:
- `terraform apply tf-first-stage`
- `terraform apply tf-second-stage`
#### Services:
- keycloak
## mirror.pkgbuild.com
@ -252,3 +281,8 @@ Example
Example
borg list borg@vostok.archlinux.org:/backup/homedir.archlinux.org::20191127-084357
## One-shots
A bunch of once-only admin task scripts can be found in `one-shots/`.
We try to minimize the amount of manual one-shot admin work we have to do but sometimes for some migrations it might be necessary to have such scripts.

View File

@ -13,3 +13,4 @@ callback_whitelist = profile_tasks
[ssh_connection]
pipelining = True
scp_if_ssh = True
retries = 5

View File

@ -14,6 +14,9 @@ arch_users:
ssh_key: aaron.pub
groups:
- dev
accounts:
name: ""
groups: []
aginiewicz:
name: "Andrzej Giniewicz"
ssh_key: aginiewicz.pub
@ -227,6 +230,7 @@ arch_users:
- name: foutrelis_buildhost.pub
hosts:
- dragon.archlinux.org
- sgp.mirror.pkgbuild.com
groups:
- dev
- tu

View File

@ -0,0 +1,14 @@
$ANSIBLE_VAULT;1.1;AES256
38386666643233373639363835396530396162636562393531373566623531346131613739386637
3238633664333561343139663665663537336633303036610a386436626330646262333130626539
35323033316530616437326630393632646630363664303765636362353063653232373233353862
6135346434373562350a376133626564643138386631366331333261376239636236343630303762
64633431326164386332396238363332303965363666663636373465626563373535343534633232
64313366623238656663383066613030633861333239623964633830323535363666303637663864
35366131663337663534393863313634376433303935363733366234326639613034363465366538
37343866306439336165666266323034666331616365333839343436306632643339386532623566
34373165323664663365663237323361643137616165666130333537653862633730646637656635
30656434366431353863333961353232653538616663313331343932363163353833633332383735
35313531333839366132343038326230643235663133373334393562393435333136363534383134
37643431666631666564383533366235313563636438666464343738376431643463373134346530
61613461326137333162346330323232333562306638353332386538386465396238

View File

@ -0,0 +1,10 @@
---
filesystem: btrfs
zabbix_agent_templates:
- Template OS Linux
- Template App Borg Backup
- Template App HTTP Service
- Template App HTTPS Service
- Template App Nginx
- Template App SSH Service
- Template App PostgreSQL

3
hosts
View File

@ -38,6 +38,8 @@ bbs.archlinux.org
homedir.archlinux.org
bugs.archlinux.org
aur-dev.archlinux.org
gitlab.archlinux.org
accounts.archlinux.org
[borg_hosts]
vostok.archlinux.org
@ -66,6 +68,7 @@ bugs.archlinux.org
[buildservers]
dragon.archlinux.org
sgp.mirror.pkgbuild.com
[gitlab_runners]
runner1.archlinux.org

3
one-shots/README.md Normal file
View File

@ -0,0 +1,3 @@
This directory contains a bunch of one-off scripts which might be modified ad-hoc in some ways.
We keep them around for documentation reasons.

View File

@ -0,0 +1,508 @@
---
arch_groups:
- dev
- tu
- devops
- fellows
- multilib
- archboxes-sudo
- docker-image-sudo
arch_users:
# aaron:
# name: "Aaron Griffin"
# ssh_key: aaron.pub
# groups:
# - dev
# aginiewicz:
# name: "Andrzej Giniewicz"
# ssh_key: aginiewicz.pub
# groups:
# - tu
# ainola:
# name: "Brett Cornwall"
# ssh_key: ainola.pub
# groups:
# - tu
# alad:
# name: "Alad Wenter"
# ssh_key: alad.pub
# groups:
# - tu
# allan:
# name: "Allan McRae"
# ssh_key: allan.pub
# groups:
# - dev
# - multilib
# - tu
# alucryd:
# name: "Maxime Gauduin"
# ssh_key: alucryd.pub
# groups:
# - dev
# - tu
# - multilib
# anatolik:
# name: "Anatol Pomozov"
# ssh_key: anatolik.pub
# groups:
# - dev
# - tu
# - multilib
# andrea:
# name: "Andrea Scarpino"
# ssh_key: andrea.pub
# groups: []
# andrew:
# name: "Andrew Gregory"
# ssh_key: andrew.pub
# groups:
# - dev
# andrewsc:
# name: "Andrew Crerar"
# ssh_key: andrewsc.pub
# groups:
# - tu
# anthraxx:
# name: "Levente Polyak"
# ssh_key: anthraxx.pub
# shell: /bin/zsh
# groups:
# - dev
# - devops
# - tu
# - multilib
# andyrtr:
# name: "Andreas Radke"
# ssh_key: andyrtr.pub
# groups:
# - dev
# - tu
# arcanis:
# name: "Evgeniy Alekseev"
# ssh_key: arcanis.pub
# groups:
# - tu
# archange:
# name: "Bruno Pagani"
# ssh_key: archange.pub
# shell: /bin/zsh
# groups:
# - tu
# - multilib
# arodseth:
# name: "Alexander Rødseth"
# ssh_key: arodseth.pub
# groups:
# - tu
# - multilib
# arojas:
# name: "Antonio Rojas"
# ssh_key: arojas.pub
# groups:
# - dev
# - tu
# - multilib
# aur-notify:
# name: ""
# groups: []
# bgyorgy:
# name: "Balló György"
# ssh_key: bgyorgy.pub
# groups:
# - tu
# bisson:
# name: "Gaëtan Bisson"
# ssh_key: bisson.pub
# groups:
# - dev
# - tu
# bluewind:
# name: "Florian Pritz"
# ssh_key: bluewind.pub
# shell: /bin/zsh
# groups:
# - dev
# - devops
# - tu
# - multilib
# bpiotrowski:
# name: "Bartłomiej Piotrowski"
# ssh_key: bpiotrowski.pub
# groups:
# - dev
# - devops
# - tu
# - multilib
# cbehan:
# name: "Connor Behan"
# ssh_key: cbehan.pub
# groups:
# - tu
# cesura:
# name: "Brad Fanella"
# ssh_key: cesura.pub
# groups:
# - tu
# coderobe:
# name: "Robin Broda"
# ssh_key: coderobe.pub
# groups:
# - tu
# daurnimator:
# name: "Daurnimator"
# ssh_key: daurnimator.pub
# groups:
# - tu
# dbermond:
# name: "Daniel Bermond"
# ssh_key: dbermond.pub
# groups:
# - tu
# demize:
# name: "Johannes Löthberg"
# ssh_key: demize.pub
# shell: /bin/zsh
# groups:
# - dev
# - tu
# - multilib
# diabonas:
# name: "Jonas Witschel"
# ssh_key: diabonas.pub
# groups:
# - tu
# donate:
# name: ""
# groups: []
# dreisner:
# name: "Dave Reisner"
# ssh_key: dreisner.pub
# groups:
# - dev
# - multilib
# - tu
# dvzrv:
# name: "David Runge"
# ssh_key: dvzrv.pub
# groups:
# - dev
# - multilib
# - tu
# eschwartz:
# name: "Eli Schwartz"
# ssh_key: eschwartz.pub
# groups:
# - tu
# - multilib
# escondida:
# name: "Ivy Foster"
# ssh_key: escondida.pub
# groups:
# - tu
# eworm:
# name: "Christian Hesse"
# ssh_key: eworm.pub
# shell: /bin/zsh
# groups:
# - dev
# - tu
# - multilib
# farseerfc:
# name: "Jiachen Yang"
# ssh_key: farseerfc.pub
# groups:
# - tu
# felixonmars:
# name: "Felix Yan"
# ssh_key: felixonmars.pub
# groups:
# - dev
# - tu
# - multilib
# ffy00:
# name: "Filipe Laíns"
# ssh_key: ffy00.pub
# shell: /bin/bash
# groups:
# - tu
# foutrelis:
# name: "Evangelos Foutras"
# ssh_key: foutrelis.pub
# additional_ssh_keys:
# - name: foutrelis_buildhost.pub
# hosts:
# - dragon.archlinux.org
# - sgp.mirror.pkgbuild.com
# groups:
# - dev
# - devops
# - tu
# - multilib
# foxboron:
# name: "Morten Linderud"
# ssh_key: foxboron.pub
# groups:
# - tu
# foxxx0:
# name: "Thore Bödecker"
# ssh_key: foxxx0.pub
# shell: /bin/zsh
# groups:
# - tu
# fukawi2:
# name: "Phillip Smith"
# ssh_key: fukawi2.pub
# groups:
# - devops
# giovanni:
# name: ""
# ssh_key: giovanni.pub
# groups:
# - dev
# - multilib
# gitlab:
# name: ""
# groups: []
# grazzolini:
# name: "Giancarlo Razzolini"
# ssh_key: grazzolini.pub
# groups:
# - dev
# - devops
# - multilib
# - tu
# heftig:
# name: "Jan Steffens"
# ssh_key: heftig.pub
# additional_ssh_keys:
# - name: heftig_work.pub
# hosts:
# - dragon.archlinux.org
# - name: heftig_dragon.pub
# hosts:
# - homedir.archlinux.org
# groups:
# - dev
# - devops
# - tu
# - multilib
# idevolder:
# name: "Ike Devolder"
# ssh_key: idevolder.pub
# groups:
# - tu
jelle:
name: "Jelle van der Waa"
ssh_key: jelle.pub
groups:
- dev
- devops
- tu
- multilib
# jgc:
# name: "Jan de Groot"
# ssh_key: jgc.pub
# groups:
# - dev
# - multilib
# - tu
# jleclanche:
# name: "Jerome Leclanche"
# ssh_key: jleclanche.pub
# shell: /bin/zsh
# groups:
# - tu
# jlichtblau:
# name: "Jaroslav Lichtblau"
# ssh_key: jlichtblau.pub
# groups:
# - tu
# jouke:
# name: "Jouke Witteveen"
# ssh_key: jouke.pub
# groups:
# - ""
# jsteel:
# name: "Jonathan Steel"
# ssh_key: jsteel.pub
# groups:
# - tu
# juergen:
# name: "Jürgen Hötzel"
# ssh_key: juergen.pub
# groups:
# - dev
# - multilib
# - tu
# kgizdov:
# name: "Konstantin Gizdov"
# ssh_key: kgizdov.pub
# groups:
# - tu
# kkeen:
# name: "Kyle Keen"
# ssh_key: kkeen.pub
# groups:
# - tu
# - multilib
# lcarlier:
# name: "Laurent Carlier"
# ssh_key: lcarlier.pub
# groups:
# - dev
# - tu
# - multilib
# lfleischer:
# name: "Lukas Fleischer"
# ssh_key: lfleischer.pub
# shell: /bin/zsh
# groups:
# - dev
# - tu
# - multilib
# maximbaz:
# name: "Maxim Baz"
# ssh_key: maximbaz.pub
# groups:
# - tu
# mtorromeo:
# name: "Massimiliano Torromeo"
# ssh_key: mtorromeo.pub
# groups:
# - tu
# muflone:
# name: "Fabio Castelli"
# ssh_key: muflone.pub
# groups:
# - tu
# nicohood:
# name: "NicoHood"
# ssh_key: nicohood.pub
# groups:
# - tu
# pierre:
# name: "Pierre Schmitz"
# ssh_key: pierre.pub
# groups:
# - dev
# - multilib
# - tu
# polyzen:
# name: "Daniel M. Capella"
# ssh_key: polyzen.pub
# groups:
# - tu
# remy:
# name: "Rémy Oudompheng"
# ssh_key: remy.pub
# groups:
# - dev
# - tu
# ronald:
# name: "Ronald van Haren"
# ssh_key: ronald.pub
# groups:
# - dev
# - tu
# sangy:
# name: "Santiago Torres-Arias"
# ssh_key: sangy.pub
# groups:
# - tu
# - docker-image-sudo
# schiv:
# name: "Ray Rashif"
# ssh_key: schiv.pub
# groups:
# - dev
# - tu
# - multilib
# schuay:
# name: "Jakob Gruber"
# ssh_key: schuay.pub
# groups:
# - tu
# - multilib
# scimmia:
# name: "Doug Newgard"
# ssh_key: scimmia.pub
# groups: []
# morganamilo:
# name: "Morgan Adamiec"
# ssh_key: morganamilo.pub
# groups: []
# seblu:
# name: "Sébastien Luttringer"
# ssh_key: seblu.pub
# shell: /bin/zsh
# groups:
# - dev
# - tu
# - multilib
# shibumi:
# name: "Christian Rebischke"
# ssh_key: shibumi.pub
# shell: /bin/zsh
# groups:
# - tu
# - archboxes-sudo
# kpcyrd:
# name: "Kpcyrd"
# ssh_key: kpcyrd.pub
# groups:
# - tu
# spupykin:
# name: "Sergej Pupykin"
# ssh_key: spupykin.pub
# groups:
# - tu
# - multilib
# svenstaro:
# name: "Sven-Hendrik Haase"
# ssh_key: svenstaro.pub
# groups:
# - dev
# - devops
# - tu
# - multilib
# tensor5:
# name: "Nicola Squartini"
# ssh_key: tensor5.pub
# groups:
# - tu
# thomas:
# name: "Thomas Bächler"
# ssh_key: thomas.pub
# groups:
# - dev
# - multilib
# tpowa:
# name: "Tobias Powalowski"
# ssh_key: tpowa.pub
# groups:
# - dev
# - multilib
# - tu
# wild:
# name: "Dan Printzell"
# ssh_key: wild.pub
# groups:
# - tu
# xyne:
# name: "Xyne"
# ssh_key: xyne.pub
# groups:
# - tu
# yan12125:
# name: "Chih-Hsuan Yen"
# ssh_key: yan12125.pub
# groups:
# - tu
# zorun:
# name: "Baptiste Jonglez"
# ssh_key: zorun.pub
# groups:
# - tu

View File

@ -0,0 +1,167 @@
#!/usr/bin/env python
import argparse
import os
import sys
import time
import webbrowser
from datetime import datetime
import requests
import yaml
IMPORT_GROUPS = {
"dev": "Developers",
"devops": "DevOps",
"tu": "Trusted Users",
}
CLIENT_ID = "admin-cli"
KEYCLOAK_ADMIN_USERNAME = os.environ["KEYCLOAK_ADMIN_USERNAME"]
KEYCLOAK_ADMIN_PASSWORD = os.environ["KEYCLOAK_ADMIN_PASSWORD"]
KEYCLOAK_URL = "https://accounts.archlinux.org/auth"
KEYCLOAK_REALM = "master"
REALM_URL = f"{KEYCLOAK_URL}/realms/{KEYCLOAK_REALM}"
FETCH_TOKEN_URL = f"{REALM_URL}/protocol/openid-connect/token"
API_BASE_URL = f"{KEYCLOAK_URL}/admin/realms/{KEYCLOAK_REALM}"
_token_expire = 0
_token_cache = ""
def get_token():
global _token_cache
global _token_expire
if _token_expire < datetime.now().timestamp():
r = requests.post(
FETCH_TOKEN_URL,
data={
"username": KEYCLOAK_ADMIN_USERNAME,
"password": KEYCLOAK_ADMIN_PASSWORD,
"grant_type": "password",
"client_id": CLIENT_ID,
},
)
data = r.json()
if "error" in data:
sys.stderr.write(
f"Error requesting token: {data.get('error_description', data['error'])}\n"
)
sys.exit(1)
_token_expire = datetime.now().timestamp() + data["expires_in"]
_token_cache = data["access_token"]
return _token_cache
def get_auth_headers():
token = get_token()
return {"Authorization": f"Bearer {token}"}
def is_valid_file(parser, arg):
if not os.path.exists(arg):
parser.error(f"File {arg!r} does not exist")
return open(arg, "r")
def add_user_to_group(user_id: str, group_id: str):
r = requests.put(
f"{API_BASE_URL}/users/{user_id}/groups/{group_id}",
data={"realm": KEYCLOAK_REALM, "userId": user_id, "groupId": group_id},
headers=get_auth_headers(),
)
if r.status_code in (200, 204):
# Success, empty response
return
else:
data = r.json()
if "error" in data:
sys.stderr.write(
f"Error adding user to group: {data.get('error_description', data['error'])}\n"
)
sys.exit(1)
def get_all_users():
all_users = requests.get(
f"{API_BASE_URL}/users",
{"briefRepresentation": "true", "first": "0", "max": "200"},
headers=get_auth_headers(),
).json()
return {u["username"]: u["id"] for u in all_users}
def get_all_groups():
all_groups = requests.get(
f"{API_BASE_URL}/groups",
{"first": "0", "max": "200"},
headers=get_auth_headers(),
).json()
return {g["name"]: g["id"] for g in all_groups}
def main():
if not KEYCLOAK_ADMIN_USERNAME or not KEYCLOAK_ADMIN_PASSWORD:
sys.stderr.write(
"Environment variables KEYCLOAK_ADMIN_USERNAME and KEYCLOAK_ADMIN_PASSWORD must be set\n"
)
exit(1)
p = argparse.ArgumentParser()
p.add_argument("file", type=lambda x: is_valid_file(p, x))
args = p.parse_args(sys.argv[1:])
users_yml = yaml.load(args.file, Loader=yaml.SafeLoader)
users = users_yml["arch_users"]
user_ids = get_all_users()
group_ids = get_all_groups()
print(user_ids)
for username, user in users.items():
if username not in user_ids:
# Check if the user has a significant role
for group in user["groups"]:
if group in IMPORT_GROUPS:
break
else:
# Otherwise, skip creating it
continue
print(f"Creating {username!r}")
name = user.get("name", "")
first_name, last_name = "", ""
if name:
_names = name.split()
if _names:
first_name = _names[0]
if len(_names) > 1:
last_name = " ".join(_names[1:])
response = requests.post(
f"{API_BASE_URL}/users",
json={
"username": username,
"email": user.get("email", ""),
"firstName": first_name,
"lastName": last_name,
"enabled": True,
},
headers=get_auth_headers(),
)
user_ids = get_all_users()
for username, user in users.items():
for group in user["groups"]:
if group in IMPORT_GROUPS:
import_group = IMPORT_GROUPS[group]
print(f"Adding {username!r} to {import_group!r}")
add_user_to_group(user_ids[username], group_ids[import_group])
if __name__ == "__main__":
main()

View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
curl -s https://accounts.archlinux.org/auth/realms/master/protocol/saml/descriptor | xmllint --xpath '//*[local-name()="X509Certificate"]/text()' - | base64 -d | sha1sum | cut -d ' ' -f1 | sed -e 's/.\{2\}/&:/g' | sed 's/:$//' | tr '[:lower:]' '[:upper:]'

View File

@ -8,3 +8,12 @@
- { role: firewalld }
- { role: sshd }
- { role: root_ssh }
- { role: certbot }
- { role: nginx }
- role: postgres
postgres_shared_buffers: 500MB
postgres_work_mem: 32MB
postgres_maintenance_work_mem: 1GB
postgres_effective_cache_size: 1GB
- { role: keycloak }
- { role: borg-client, tags: ["borg"] }

View File

@ -10,3 +10,4 @@
- { role: sshd }
- { role: root_ssh }
- { role: gitlab, gitlab_domain: "gitlab.archlinux.org" }
- { role: borg-client, tags: ["borg"] }

View File

@ -19,6 +19,11 @@
restart_policy: always
env:
# See https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-config-template/gitlab.rb.template
# 1. In order to figure out what needs to go into 'idp_cert_fingerprint', run
# one-shots/keycloak-keyfetcher/get_fingerprint.sh and copy the resulting SHA1 fingerprint into that field.
# 2. In order to logout properly we need to configure the "After sign out path" and set it to
# https://accounts.archlinux.org/auth/realms/master/protocol/openid-connect/logout?redirect_uri=https%3A//gitlab.archlinux.org
# https://gitlab.com/gitlab-org/gitlab/issues/14414
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://{{ gitlab_domain }}'
letsencrypt['enable'] = true
@ -38,6 +43,32 @@
gitlab_rails['gitlab_email_display_name'] = 'GitLab'
gitlab_rails['gitlab_email_reply_to'] = 'noreply@archlinux.org'
gitlab_rails['gitlab_default_theme'] = 2
gitlab_rails['omniauth_allow_single_sign_on'] = ['saml']
gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_auto_link_saml_user'] = true
gitlab_rails['omniauth_providers'] = [
{
name: 'saml',
label: 'Arch Linux SSO',
groups_attribute: 'Role',
admin_groups: ['DevOps'],
args: {
assertion_consumer_service_url: 'https://gitlab.archlinux.org/users/auth/saml/callback',
idp_cert_fingerprint: '83:AB:61:8E:8C:8A:78:F6:D9:A6:8E:25:6F:DA:04:4D:77:0E:CD:B2',
idp_sso_target_url: 'https://accounts.archlinux.org/auth/realms/master/protocol/saml/clients/saml_gitlab',
idp_slo_target_url: 'https://accounts.archlinux.org/auth/realms/master/protocol/saml',
issuer: 'saml_gitlab',
attribute_statements: {
first_name: ['first_name'],
last_name: ['last_name'],
name: ['name'],
username: ['username'],
email: ['email'],
},
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
}
}
]
volumes:
- "/srv/gitlab/config:/etc/gitlab"
- "/srv/gitlab/logs:/var/log/gitlab"

View File

@ -0,0 +1,6 @@
keycloak_db_name: keycloak
keycloak_db_user: keycloak
keycloak_db_password: keycloak
keycloak_domain: accounts.archlinux.org
keycloak_home_dir: /opt/keycloak
keycloak_port: "8443"

View File

@ -0,0 +1,4 @@
---
- name: restart keycloak
service: name=keycloak state=restarted

View File

@ -3,16 +3,46 @@
- name: install keycloak
pacman: name=keycloak state=present
# - name: start dirsrv service
# service: name=dirsrv
# Levente TODO
- name: template keycloak config
template: src=standalone.xml.j2 dest=/etc/keycloak/standalone.xml owner=keycloak group=keycloak mode=600
notify:
- restart keycloak
# - name: open firewall hole
# firewalld: port={{ item }} permanent=true state=enabled immediate=yes
# when: configure_firewall
# with_items:
# Levente TODO
# - 389
# - 636
# tags:
# - firewall
- name: create an admin user
command: /opt/keycloak/bin/add-user-keycloak.sh -u "{{ vault_keycloak_admin_user }}" -p "{{ vault_keycloak_admin_password }}"
args:
creates: /opt/keycloak/standalone/configuration/keycloak-add-user.json
- name: start and enable keycloak
service: name=keycloak enabled=yes state=started
- name: open firewall hole
firewalld: port={{ item }} permanent=true state=enabled immediate=yes
when: configure_firewall
with_items:
- 80/tcp
- 443/tcp
tags:
- firewall
- name: create postgres keycloak user
postgresql_user: name="{{ keycloak_db_user }}" password="{{ keycloak_db_password }}"
become: yes
become_user: postgres
become_method: su
no_log: True
- name: create keycloak db
postgresql_db: name=keycloak owner="{{ keycloak_db_user }}"
become: yes
become_user: postgres
become_method: su
- name: make nginx log dir
file: path="/var/log/nginx/{{ keycloak_domain }}" state=directory owner=root mode=0755
- name: set up nginx
template: src=nginx.d.conf.j2 dest=/etc/nginx/nginx.d/keycloak.conf owner=root group=root mode=0644
notify:
- reload nginx
tags: ['nginx']

View File

@ -1,28 +0,0 @@
[general]
config_version = 2
full_machine_name = {{ inventory_hostname}}
selinux = False
start = False
strict_host_checking = True
systemd = True
[slapd]
instance_name = archlinux
root_dn = cn=Administrator
root_password = {{ vault_ldap_dir_manager_password }}
port = 389
secure_port = 636
self_sign_cert = True
self_sign_cert_valid_months = 24
backup_dir = /var/lib/dirsrv/slapd-{instance_name}/bak
cert_dir = /etc/dirsrv/slapd-{instance_name}
config_dir = /etc/dirsrv/slapd-{instance_name}
db_dir = /var/lib/dirsrv/slapd-{instance_name}/db
inst_dir = /usr/lib/dirsrv/slapd-{instance_name}
ldif_dir = /var/lib/dirsrv/slapd-{instance_name}/ldif
lock_dir = /var/lock/dirsrv/slapd-{instance_name}
log_dir = /var/log/dirsrv/slapd-{instance_name}
schema_dir = /etc/dirsrv/slapd-{instance_name}/schema
[backend-userroot]
suffix = dc=archlinux,dc=org

View File

@ -0,0 +1,37 @@
server {
listen 80;
listen [::]:80;
server_name {{ keycloak_domain }};
access_log /var/log/nginx/{{ keycloak_domain }}/access.log reduced;
error_log /var/log/nginx/{{ keycloak_domain }}/error.log;
include snippets/letsencrypt.conf;
location / {
access_log off;
return 301 https://$server_name$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name {{ keycloak_domain }};
access_log /var/log/nginx/{{ keycloak_domain }}/access.log reduced;
error_log /var/log/nginx/{{ keycloak_domain }}/error.log;
ssl_certificate /etc/letsencrypt/live/{{ keycloak_domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ keycloak_domain }}/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/{{ keycloak_domain }}/chain.pem;
root {{ keycloak_domain }};
location / {
access_log /var/log/nginx/{{ keycloak_domain }}/access.log main;
proxy_pass https://localhost:{{ keycloak_port }};
proxy_set_header Host $host;
proxy_ssl_verify off;
}
}

View File

@ -0,0 +1,591 @@
<?xml version="1.0" encoding="UTF-8"?>
<server xmlns="urn:jboss:domain:10.0">
<extensions>
<extension module="org.jboss.as.clustering.infinispan"/>
<extension module="org.jboss.as.connector"/>
<extension module="org.jboss.as.deployment-scanner"/>
<extension module="org.jboss.as.ee"/>
<extension module="org.jboss.as.ejb3"/>
<extension module="org.jboss.as.jaxrs"/>
<extension module="org.jboss.as.jmx"/>
<extension module="org.jboss.as.jpa"/>
<extension module="org.jboss.as.logging"/>
<extension module="org.jboss.as.mail"/>
<extension module="org.jboss.as.naming"/>
<extension module="org.jboss.as.remoting"/>
<extension module="org.jboss.as.security"/>
<extension module="org.jboss.as.transactions"/>
<extension module="org.jboss.as.weld"/>
<extension module="org.keycloak.keycloak-server-subsystem"/>
<extension module="org.wildfly.extension.bean-validation"/>
<extension module="org.wildfly.extension.core-management"/>
<extension module="org.wildfly.extension.elytron"/>
<extension module="org.wildfly.extension.io"/>
<extension module="org.wildfly.extension.microprofile.config-smallrye"/>
<extension module="org.wildfly.extension.microprofile.health-smallrye"/>
<extension module="org.wildfly.extension.microprofile.metrics-smallrye"/>
<extension module="org.wildfly.extension.request-controller"/>
<extension module="org.wildfly.extension.security.manager"/>
<extension module="org.wildfly.extension.undertow"/>
</extensions>
<management>
<security-realms>
<security-realm name="ManagementRealm">
<authentication>
<local default-user="$local" skip-group-loading="true"/>
<properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization map-groups-to-roles="false">
<properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
<security-realm name="ApplicationRealm">
<server-identities>
<ssl>
<keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/>
</ssl>
</server-identities>
<authentication>
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
<properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization>
<properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
</security-realms>
<audit-log>
<formatters>
<json-formatter name="json-formatter"/>
</formatters>
<handlers>
<file-handler name="file" formatter="json-formatter" path="audit-log.log" relative-to="jboss.server.data.dir"/>
</handlers>
<logger log-boot="true" log-read-only="false" enabled="false">
<handlers>
<handler name="file"/>
</handlers>
</logger>
</audit-log>
<management-interfaces>
<http-interface security-realm="ManagementRealm">
<http-upgrade enabled="true"/>
<socket-binding http="management-http"/>
</http-interface>
</management-interfaces>
<access-control provider="simple">
<role-mapping>
<role name="SuperUser">
<include>
<user name="$local"/>
</include>
</role>
</role-mapping>
</access-control>
</management>
<profile>
<subsystem xmlns="urn:jboss:domain:logging:8.0">
<console-handler name="CONSOLE">
<level name="INFO"/>
<formatter>
<named-formatter name="COLOR-PATTERN"/>
</formatter>
</console-handler>
<periodic-rotating-file-handler name="FILE" autoflush="true">
<formatter>
<named-formatter name="PATTERN"/>
</formatter>
<file relative-to="jboss.server.log.dir" path="server.log"/>
<suffix value=".yyyy-MM-dd"/>
<append value="true"/>
</periodic-rotating-file-handler>
<logger category="com.arjuna">
<level name="WARN"/>
</logger>
<logger category="io.jaegertracing.Configuration">
<level name="WARN"/>
</logger>
<logger category="org.jboss.as.config">
<level name="DEBUG"/>
</logger>
<logger category="sun.rmi">
<level name="WARN"/>
</logger>
<root-logger>
<level name="INFO"/>
<handlers>
<handler name="CONSOLE"/>
<handler name="FILE"/>
</handlers>
</root-logger>
<formatter name="PATTERN">
<pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
<formatter name="COLOR-PATTERN">
<pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
</formatter>
</subsystem>
<subsystem xmlns="urn:jboss:domain:bean-validation:1.0"/>
<subsystem xmlns="urn:jboss:domain:core-management:1.0"/>
<subsystem xmlns="urn:jboss:domain:datasources:5.0">
<datasources>
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:postgresql://localhost:5432/keycloak</connection-url>
<driver>postgresql</driver>
<security>
<user-name>keycloak</user-name>
<password>keycloak</password>
</security>
</datasource>
<drivers>
<driver name="postgresql" module="org.postgresql">
<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
</driver>
<driver name="h2" module="com.h2database.h2">
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
<subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
<deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ee:4.0">
<spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
<concurrent>
<context-services>
<context-service name="default" jndi-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true"/>
</context-services>
<managed-thread-factories>
<managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default"/>
</managed-thread-factories>
<managed-executor-services>
<managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-threshold="60000" keepalive-time="5000"/>
</managed-executor-services>
<managed-scheduled-executor-services>
<managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-threshold="60000" keepalive-time="3000"/>
</managed-scheduled-executor-services>
</concurrent>
<default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:jboss/datasources/KeycloakDS" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:ejb3:6.0">
<session-bean>
<stateless>
<bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
</stateless>
<stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
<singleton default-access-timeout="5000"/>
</session-bean>
<pools>
<bean-instance-pools>
<strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
<strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
</bean-instance-pools>
</pools>
<caches>
<cache name="simple"/>
<cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
</caches>
<passivation-stores>
<passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
</passivation-stores>
<async thread-pool-name="default"/>
<timer-service thread-pool-name="default" default-data-store="default-file-store">
<data-stores>
<file-data-store name="default-file-store" path="timer-service-data" relative-to="jboss.server.data.dir"/>
</data-stores>
</timer-service>
<remote connector-ref="http-remoting-connector" thread-pool-name="default">
<channel-creation-options>
<option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
</channel-creation-options>
</remote>
<thread-pools>
<thread-pool name="default">
<max-threads count="10"/>
<keepalive-time time="60" unit="seconds"/>
</thread-pool>
</thread-pools>
<default-security-domain value="other"/>
<default-missing-method-permissions-deny-access value="true"/>
<statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<log-system-exceptions value="true"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:io:3.0">
<worker name="default"/>
<buffer-pool name="default"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:infinispan:9.0">
<cache-container name="keycloak">
<local-cache name="realms">
<object-memory size="10000"/>
</local-cache>
<local-cache name="users">
<object-memory size="10000"/>
</local-cache>
<local-cache name="sessions"/>
<local-cache name="authenticationSessions"/>
<local-cache name="offlineSessions"/>
<local-cache name="clientSessions"/>
<local-cache name="offlineClientSessions"/>
<local-cache name="loginFailures"/>
<local-cache name="work"/>
<local-cache name="authorization">
<object-memory size="10000"/>
</local-cache>
<local-cache name="keys">
<object-memory size="1000"/>
<expiration max-idle="3600000"/>
</local-cache>
<local-cache name="actionTokens">
<object-memory size="-1"/>
<expiration max-idle="-1" interval="300000"/>
</local-cache>
</cache-container>
<cache-container name="server" default-cache="default" module="org.wildfly.clustering.server">
<local-cache name="default">
<transaction mode="BATCH"/>
</local-cache>
</cache-container>
<cache-container name="web" default-cache="passivation" module="org.wildfly.clustering.web.infinispan">
<local-cache name="passivation">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store passivation="true" purge="false"/>
</local-cache>
<local-cache name="sso">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
</local-cache>
<local-cache name="routing"/>
</cache-container>
<cache-container name="ejb" aliases="sfsb" default-cache="passivation" module="org.wildfly.clustering.ejb.infinispan">
<local-cache name="passivation">
<locking isolation="REPEATABLE_READ"/>
<transaction mode="BATCH"/>
<file-store passivation="true" purge="false"/>
</local-cache>
</cache-container>
<cache-container name="hibernate" module="org.infinispan.hibernate-cache">
<local-cache name="entity">
<object-memory size="10000"/>
<expiration max-idle="100000"/>
</local-cache>
<local-cache name="local-query">
<object-memory size="10000"/>
<expiration max-idle="100000"/>
</local-cache>
<local-cache name="timestamps"/>
</cache-container>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jaxrs:1.0"/>
<subsystem xmlns="urn:jboss:domain:jca:5.0">
<archive-validation enabled="true" fail-on-error="true" fail-on-warn="false"/>
<bean-validation enabled="true"/>
<default-workmanager>
<short-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</short-running-threads>
<long-running-threads>
<core-threads count="50"/>
<queue-length count="50"/>
<max-threads count="50"/>
<keepalive-time time="10" unit="seconds"/>
</long-running-threads>
</default-workmanager>
<cached-connection-manager/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jmx:1.3">
<expose-resolved-model/>
<expose-expression-model/>
<remoting-connector/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:jpa:1.1">
<jpa default-datasource="" default-extended-persistence-inheritance="DEEP"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:mail:3.0">
<mail-session name="default" jndi-name="java:jboss/mail/Default">
<smtp-server outbound-socket-binding-ref="mail-smtp"/>
</mail-session>
</subsystem>
<subsystem xmlns="urn:jboss:domain:naming:2.0">
<remote-naming/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:remoting:4.0">
<http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:request-controller:1.0"/>
<subsystem xmlns="urn:jboss:domain:security-manager:1.0">
<deployment-permissions>
<maximum-set>
<permission class="java.security.AllPermission"/>
</maximum-set>
</deployment-permissions>
</subsystem>
<subsystem xmlns="urn:wildfly:elytron:8.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
<providers>
<aggregate-providers name="combined-providers">
<providers name="elytron"/>
<providers name="openssl"/>
</aggregate-providers>
<provider-loader name="elytron" module="org.wildfly.security.elytron"/>
<provider-loader name="openssl" module="org.wildfly.openssl"/>
</providers>
<audit-logging>
<file-audit-log name="local-audit" path="audit.log" relative-to="jboss.server.log.dir" format="JSON"/>
</audit-logging>
<security-domains>
<security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
<realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
<realm name="local"/>
</security-domain>
<security-domain name="ManagementDomain" default-realm="ManagementRealm" permission-mapper="default-permission-mapper">
<realm name="ManagementRealm" role-decoder="groups-to-roles"/>
<realm name="local" role-mapper="super-user-mapper"/>
</security-domain>
</security-domains>
<security-realms>
<identity-realm name="local" identity="$local"/>
<properties-realm name="ApplicationRealm">
<users-properties path="application-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ApplicationRealm"/>
<groups-properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
<properties-realm name="ManagementRealm">
<users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir" digest-realm-name="ManagementRealm"/>
<groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
</properties-realm>
</security-realms>
<mappers>
<simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
<permission-mapping>
<principal name="anonymous"/>
<permission-set name="default-permissions"/>
</permission-mapping>
<permission-mapping match-all="true">
<permission-set name="login-permission"/>
<permission-set name="default-permissions"/>
</permission-mapping>
</simple-permission-mapper>
<constant-realm-mapper name="local" realm-name="local"/>
<simple-role-decoder name="groups-to-roles" attribute="groups"/>
<constant-role-mapper name="super-user-mapper">
<role name="SuperUser"/>
</constant-role-mapper>
</mappers>
<permission-sets>
<permission-set name="login-permission">
<permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
</permission-set>
<permission-set name="default-permissions">
<permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission" module="org.wildfly.extension.batch.jberet" target-name="*"/>
<permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission" module="org.wildfly.transaction.client"/>
<permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
</permission-set>
</permission-sets>
<http>
<http-authentication-factory name="management-http-authentication" security-domain="ManagementDomain" http-server-mechanism-factory="global">
<mechanism-configuration>
<mechanism mechanism-name="DIGEST">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</http-authentication-factory>
<provider-http-server-mechanism-factory name="global"/>
</http>
<sasl>
<sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured" security-domain="ApplicationDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ApplicationRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<sasl-authentication-factory name="management-sasl-authentication" sasl-server-factory="configured" security-domain="ManagementDomain">
<mechanism-configuration>
<mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
<mechanism mechanism-name="DIGEST-MD5">
<mechanism-realm realm-name="ManagementRealm"/>
</mechanism>
</mechanism-configuration>
</sasl-authentication-factory>
<configurable-sasl-server-factory name="configured" sasl-server-factory="elytron">
<properties>
<property name="wildfly.sasl.local-user.default-user" value="$local"/>
</properties>
</configurable-sasl-server-factory>
<mechanism-provider-filtering-sasl-server-factory name="elytron" sasl-server-factory="global">
<filters>
<filter provider-name="WildFlyElytron"/>
</filters>
</mechanism-provider-filtering-sasl-server-factory>
<provider-sasl-server-factory name="global"/>
</sasl>
</subsystem>
<subsystem xmlns="urn:jboss:domain:security:2.0">
<security-domains>
<security-domain name="other" cache-type="default">
<authentication>
<login-module code="Remoting" flag="optional">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
<login-module code="RealmDirect" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
</authentication>
</security-domain>
<security-domain name="jboss-web-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
<security-domain name="jaspitest" cache-type="default">
<authentication-jaspi>
<login-module-stack name="dummy">
<login-module code="Dummy" flag="optional"/>
</login-module-stack>
<auth-module code="Dummy"/>
</authentication-jaspi>
</security-domain>
<security-domain name="jboss-ejb-policy" cache-type="default">
<authorization>
<policy-module code="Delegating" flag="required"/>
</authorization>
</security-domain>
</security-domains>
</subsystem>
<subsystem xmlns="urn:jboss:domain:transactions:5.0">
<core-environment node-identifier="${jboss.tx.node.id:1}">
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
<coordinator-environment statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
<object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
</subsystem>
<subsystem xmlns="urn:jboss:domain:weld:4.0"/>
<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0"/>
<subsystem xmlns="urn:wildfly:microprofile-health-smallrye:2.0" security-enabled="false" empty-liveness-checks-status="${env.MP_HEALTH_EMPTY_LIVENESS_CHECKS_STATUS:UP}" empty-readiness-checks-status="${env.MP_HEALTH_EMPTY_READINESS_CHECKS_STATUS:UP}"/>
<subsystem xmlns="urn:wildfly:microprofile-metrics-smallrye:2.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:wildfly}"/>
<subsystem xmlns="urn:jboss:domain:undertow:10.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<buffer-cache name="default"/>
<server name="default-server">
<http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>
<https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<http-invoker security-realm="ApplicationRealm"/>
</host>
</server>
<servlet-container name="default">
<jsp-config/>
<websockets/>
</servlet-container>
<handlers>
<file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
</handlers>
</subsystem>
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
<web-context>auth</web-context>
<providers>
<provider>classpath:${jboss.home.dir}/providers/*</provider>
</providers>
<master-realm-name>master</master-realm-name>
<scheduled-task-interval>900</scheduled-task-interval>
<theme>
<staticMaxAge>2592000</staticMaxAge>
<cacheThemes>true</cacheThemes>
<cacheTemplates>true</cacheTemplates>
<dir>${jboss.home.dir}/themes</dir>
</theme>
<spi name="eventsStore">
<provider name="jpa" enabled="true">
<properties>
<property name="exclude-events" value="[&quot;REFRESH_TOKEN&quot;]"/>
</properties>
</provider>
</spi>
<spi name="userCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="userSessionPersister">
<default-provider>jpa</default-provider>
</spi>
<spi name="timer">
<default-provider>basic</default-provider>
</spi>
<spi name="connectionsHttpClient">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsJpa">
<provider name="default" enabled="true">
<properties>
<property name="dataSource" value="java:jboss/datasources/KeycloakDS"/>
<property name="initializeEmpty" value="true"/>
<property name="migrationStrategy" value="update"/>
<property name="migrationExport" value="${jboss.home.dir}/keycloak-database-update.sql"/>
</properties>
</provider>
</spi>
<spi name="realmCache">
<provider name="default" enabled="true"/>
</spi>
<spi name="connectionsInfinispan">
<default-provider>default</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="cacheContainer" value="java:jboss/infinispan/container/keycloak"/>
</properties>
</provider>
</spi>
<spi name="jta-lookup">
<default-provider>${keycloak.jta.lookup.provider:jboss}</default-provider>
<provider name="jboss" enabled="true"/>
</spi>
<spi name="publicKeyStorage">
<provider name="infinispan" enabled="true">
<properties>
<property name="minTimeBetweenRequests" value="10"/>
</properties>
</provider>
</spi>
<spi name="x509cert-lookup">
<default-provider>${keycloak.x509cert.lookup.provider:default}</default-provider>
<provider name="default" enabled="true"/>
</spi>
<spi name="hostname">
<default-provider>default</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="frontendUrl" value="${keycloak.frontendUrl:}"/>
<property name="forceBackendUrlToFrontendUrl" value="false"/>
</properties>
</provider>
</spi>
</subsystem>
</profile>
<interfaces>
<interface name="management">
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
</interface>
<interface name="public">
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>
<socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
<socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">
<remote-destination host="localhost" port="25"/>
</outbound-socket-binding>
</socket-binding-group>
</server>

View File

@ -1,10 +1,11 @@
terraform {
backend "pg" {
schema_name = "terraform_remote_state_stage1"
}
}
data "external" "hetzner_cloud_api_key" {
program = ["${path.module}/misc/get_key.py", "misc/vault_hetzner.yml", "hetzner_cloud_api_key", "json"]
program = ["${path.module}/../misc/get_key.py", "misc/vault_hetzner.yml", "hetzner_cloud_api_key", "json"]
}
data "hcloud_image" "archlinux" {
@ -71,7 +72,7 @@ resource "hcloud_rdns" "gitlab" {
resource "hcloud_server" "gitlab" {
name = "gitlab.archlinux.org"
image = data.hcloud_image.archlinux.id
server_type = "cx21"
server_type = "cx31"
lifecycle {
ignore_changes = [image]
}
@ -117,6 +118,10 @@ resource "hcloud_server" "accounts" {
name = "accounts.archlinux.org"
image = data.hcloud_image.archlinux.id
server_type = "cx11"
provisioner "local-exec" {
working_dir = ".."
command = "ansible-playbook --ssh-extra-args '-o StrictHostKeyChecking=no' playbooks/accounts.archlinux.org.yml"
}
lifecycle {
ignore_changes = [image]
}
@ -187,3 +192,33 @@ resource "hcloud_server" "aur-dev" {
ignore_changes = [image]
}
}
resource "hcloud_rdns" "mailman3" {
server_id = hcloud_server.mailman3.id
ip_address = hcloud_server.mailman3.ipv4_address
dns_ptr = "mailman3.archlinux.org"
}
resource "hcloud_server" "mailman3" {
name = "mailman3.archlinux.org"
image = data.hcloud_image.archlinux.id
server_type = "cx11"
lifecycle {
ignore_changes = [image]
}
}
resource "hcloud_rdns" "reproducible" {
server_id = hcloud_server.reproducible.id
ip_address = hcloud_server.reproducible.ipv4_address
dns_ptr = "reproducible.archlinux.org"
}
resource "hcloud_server" "reproducible" {
name = "reproducible.archlinux.org"
image = data.hcloud_image.archlinux.id
server_type = "cx11"
lifecycle {
ignore_changes = [image]
}
}

167
tf-stage2/keycloak.tf Normal file
View File

@ -0,0 +1,167 @@
terraform {
backend "pg" {
schema_name = "terraform_remote_state_stage2"
}
}
data "external" "keycloak_admin_user" {
program = ["${path.module}/../misc/get_key.py", "group_vars/all/vault_keycloak.yml", "vault_keycloak_admin_user", "json"]
}
data "external" "keycloak_admin_password" {
program = ["${path.module}/../misc/get_key.py", "group_vars/all/vault_keycloak.yml", "vault_keycloak_admin_password", "json"]
}
data "external" "keycloak_smtp_user" {
program = ["${path.module}/../misc/get_key.py", "group_vars/all/vault_keycloak.yml", "vault_keycloak_smtp_user", "json"]
}
data "external" "keycloak_smtp_password" {
program = ["${path.module}/../misc/get_key.py", "group_vars/all/vault_keycloak.yml", "vault_keycloak_smtp_password", "json"]
}
provider "keycloak" {
client_id = "admin-cli"
username = data.external.keycloak_admin_user.result.vault_keycloak_admin_user
password = data.external.keycloak_admin_password.result.vault_keycloak_admin_password
url = "https://accounts.archlinux.org"
}
variable "gitlab_instance" {
default = {
root_url = "https://gitlab.archlinux.org"
saml_redirect_url = "https://gitlab.archlinux.org/users/auth/saml/callback"
}
}
resource "keycloak_realm" "master" {
realm = "master"
enabled = true
remember_me = true
display_name = "Arch Linux"
reset_password_allowed = true
verify_email = true
smtp_server {
host = "mail.archlinux.org"
from = "accounts@archlinux.org"
port = "587"
from_display_name = "Arch Linux Accounts"
ssl = false
starttls = true
auth {
username = data.external.keycloak_smtp_user.result.vault_keycloak_smtp_user
password = data.external.keycloak_smtp_password.result.vault_keycloak_smtp_password
}
}
}
resource "keycloak_saml_client" "saml_gitlab" {
realm_id = "master" // "${keycloak_realm.realm.id}"
client_id = "saml_gitlab"
name = "Arch Linux Accounts"
enabled = true
sign_documents = true
sign_assertions = true
// access_type = "CONFIDENTIAL"
valid_redirect_uris = [
var.gitlab_instance.saml_redirect_url
]
root_url = var.gitlab_instance.root_url
base_url = "/" // needed?
master_saml_processing_url = var.gitlab_instance.saml_redirect_url // needed?
// idp_initiated_sso_url_name = self.client_id
idp_initiated_sso_url_name = "saml_gitlab"
assertion_consumer_post_url = var.gitlab_instance.saml_redirect_url
}
resource "keycloak_saml_user_property_protocol_mapper" "gitlab_saml_email" {
realm_id = "master"
client_id = keycloak_saml_client.saml_gitlab.id
name = "email"
user_property = "Email"
friendly_name = "Email"
saml_attribute_name = "email"
saml_attribute_name_format = "Basic"
}
resource "keycloak_saml_user_property_protocol_mapper" "gitlab_saml_name" {
realm_id = "master"
client_id = keycloak_saml_client.saml_gitlab.id
name = "name"
user_property = "Username"
friendly_name = "Username"
saml_attribute_name = "name"
saml_attribute_name_format = "Basic"
}
resource "keycloak_saml_user_property_protocol_mapper" "gitlab_saml_first_name" {
realm_id = "master"
client_id = keycloak_saml_client.saml_gitlab.id
name = "first_name"
user_property = "FirstName"
friendly_name = "First Name"
saml_attribute_name = "first_name"
saml_attribute_name_format = "Basic"
}
resource "keycloak_saml_user_property_protocol_mapper" "gitlab_saml_last_name" {
realm_id = "master"
client_id = keycloak_saml_client.saml_gitlab.id
name = "last_name"
user_property = "LastName"
friendly_name = "Last Name"
saml_attribute_name = "last_name" // maybe just name
saml_attribute_name_format = "Basic"
}
variable "arch_groups" {
type = set(string)
default = ["DevOps", "Developers", "Trusted Users"]
}
resource "keycloak_group" "arch_groups" {
for_each = var.arch_groups
realm_id = "master"
name = each.value
}
resource "keycloak_role" "devops" {
realm_id = "master"
name = "DevOps"
description = "DevOps role"
}
resource "keycloak_group_roles" "group_roles" {
realm_id = "master"
group_id = keycloak_group.arch_groups["DevOps"].id
role_ids = [
keycloak_role.devops.id
]
}
output "gitlab_saml_configuration" {
value = {
issuer = keycloak_saml_client.saml_gitlab.client_id
assertion_consumer_service_url = var.gitlab_instance.saml_redirect_url
admin_groups = [keycloak_role.devops.name]
idp_sso_target_url = "https://accounts.archlinux.org/auth/realms/master/protocol/saml/clients/${keycloak_saml_client.saml_gitlab.client_id}"
signing_certificate_fingerprint = keycloak_saml_client.saml_gitlab.signing_certificate
}
}

View File

@ -1,4 +0,0 @@
terraform {
required_version = ">= 0.12"
}