Initial commit

This commit is contained in:
Sonny Bakker 2021-01-31 23:32:33 +01:00
commit b16f2585c7
19 changed files with 690 additions and 0 deletions

16
.gitignore vendored Normal file
View file

@ -0,0 +1,16 @@
*.retry
*.swp
.venv
.env
env
venv
node_modules/
.vault
.vaults/
vault
vaults/
roles/

26
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,26 @@
stages:
- lint
- test
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- .cache/pip
- node_modules/
lint:
stage: lint
image: node:12
before_script:
- npm install prettier --no-save
script:
- npx prettier '**/*.yml' --check
syntax-test:
stage: test
image: python:3.7
before_script:
- pip install ansible --quiet
- ansible-galaxy install -r requirements.yml
script:
- ansible-playbook playbook.yml --syntax-check

5
.prettierrc.yml Normal file
View file

@ -0,0 +1,5 @@
singleQuote: true
printWidth: 90
tabWidth: 2
useTabs: false
bracketSpacing: true

4
ansible.cfg Normal file
View file

@ -0,0 +1,4 @@
[defaults]
roles_path = ./roles
remote_user = ansible
inventory = ./inventory.yml

5
handlers.yml Normal file
View file

@ -0,0 +1,5 @@
- name: restart sentry
systemd:
name: sentry
state: restarted
enabled: true

3
inventory.yml Normal file
View file

@ -0,0 +1,3 @@
sentry:
hosts:
192.168.178.73:

33
playbook.yml Normal file
View file

@ -0,0 +1,33 @@
- hosts: sentry
pre_tasks:
- include_role:
name: common
tasks_from: 'setup.yml'
- include_role:
name: common
tasks_from: 'network.yml'
- include_role:
name: common
tasks_from: 'host.yml'
- include_role:
name: common
tasks_from: 'sudoers.yml'
loop:
- { src: '../../templates/sudoers.j2', dest: '/etc/sudoers.d/30-ansible-extra' }
roles:
- common
tasks:
- include_role:
name: common
tasks_from: 'ssl.yml'
- include_role:
name: common
tasks_from: 'nginx.yml'
- import_tasks: 'tasks/docker.yml'
- import_tasks: 'tasks/main.yml'
handlers:
- import_tasks: 'handlers.yml'
vars_files:
- 'vars/main.yml'
- 'vars/network.yml'
- 'vars/postgres.yml'

4
requirements.yml Normal file
View file

@ -0,0 +1,4 @@
- src: git+https://git.fudiggity.nl/ansible/common.git
name: common
version: master
scm: git

42
tasks/docker.yml Normal file
View file

@ -0,0 +1,42 @@
- name: add docker gpg key
apt_key:
id: '0EBFCD88'
url: 'https://download.docker.com/linux/debian/gpg'
validate_certs: true
state: present
- name: add docker repo
apt_repository:
repo: 'deb https://download.docker.com/linux/debian buster stable'
validate_certs: true
state: present
- name: install docker
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
state: present
- name: check docker-compose existence
stat:
path: '/usr/local/bin/docker-compose'
register: docker_compose_stat
- name: download docker-compose
get_url:
url: 'https://github.com/docker/compose/releases/download/1.26.0/docker-compose-Linux-x86_64'
dest: '/usr/local/bin/docker-compose'
mode: '0755'
when: docker_compose_stat.stat.isfile is not defined
- name: add sentry user
user:
name: sentry
create_home: true
shell: '/bin/bash'
groups:
- sudo
- docker
append: true

93
tasks/main.yml Normal file
View file

@ -0,0 +1,93 @@
- name: copy firewall templates
template:
src: '{{ item.src }}'
dest: '{{ item.dest }}'
owner: root
group: root
mode: '0600'
loop:
- { src: 'templates/nftables.j2', dest: '/etc/nftables.conf' }
notify: restart nftables
- name: create sites directory
file:
path: '/srv/sites'
state: directory
owner: root
group: root
mode: 0755
- name: create sentry dir
file:
path: '{{ app_dir }}'
state: directory
owner: '{{ app_user }}'
group: '{{ app_user }}'
mode: 0755
- name: clone project
become_user: '{{ app_user }}'
become: true
git:
repo: '{{ app_repository }}'
dest: '{{ app_dir }}'
version: '{{ app_branch }}'
update: true
- name: copy over sentry configurations
template:
src: '{{ item.src }}'
dest: '{{ item.dest }}'
owner: '{{ app_user }}'
group: '{{ app_user }}'
mode: '0644'
loop:
- { src: 'templates/sentry.conf.j2', dest: '{{ app_dir }}/sentry/sentry.conf.py' }
- { src: 'templates/sentry.config.j2', dest: '{{ app_dir }}/sentry/config.yml' }
- name: ensure sentry is stopped
systemd:
name: sentry
state: stopped
# can be ran multiple times to upgrade sentry
- name: run sentry installer
command: './install.sh' # noqa 301
args:
chdir: '{{ app_dir }}'
environment:
SENTRY_IMAGE: 'getsentry/sentry:{{ app_branch }}'
- name: copy sentry systemd service
template:
src: '{{ item.src }}'
dest: '{{ item.dest }}'
owner: '{{ app_user }}'
group: '{{ app_user }}'
mode: '0644'
loop:
- { src: 'templates/sentry.systemd.j2', dest: '/etc/systemd/system/sentry.service' }
notify: restart sentry
- name: copy nginx sentry config
template:
src: 'templates/nginx.j2'
dest: '/etc/nginx/sites-available/{{ app_name }}'
owner: root
group: root
mode: '0644'
- name: link nginx config
file:
src: '/etc/nginx/sites-available/{{ app_name }}'
dest: '/etc/nginx/sites-enabled/{{ app_name }}'
owner: root
group: root
mode: '0777'
state: link
- name: ensure nginx is restarted
systemd:
name: nginx
state: restarted
enabled: true

33
templates/nftables.j2 Normal file
View file

@ -0,0 +1,33 @@
# {{ ansible_managed }} {{ ansible_date_time.time }} {{ ansible_date_time.date }}
#
# vim:set ts=2 sw=2 et:
# use uppercase table names for compatibility with docker
flush ruleset
table inet filter {
chain INPUT {
type filter hook input priority 0; policy drop;
# accept any localhost traffic
iif lo accept
# accept traffic originated from us
ct state { established, related } accept
tcp dport { 22, 80, 443 } accept
}
chain FORWARD {
type filter hook forward priority 0; policy drop;
ct state { established, related } accept;
mark 1 accept
}
}
table ip filter {
chain DOCKER-USER {
mark set 1
}
}

26
templates/nginx.j2 Normal file
View file

@ -0,0 +1,26 @@
# {{ ansible_managed }} {{ ansible_date_time.time }} {{ ansible_date_time.date }}
#
server {
listen 80;
server_name {{ app_name }}.fudiggity.nl;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name {{ app_name }}.fudiggity.nl;
ssl_certificate /etc/ssl/{{ app_name }}/{{ app_name }}.crt;
ssl_certificate_key /etc/ssl/{{ app_name }}/local.pem;
access_log /var/log/nginx/{{ app_name }}.log;
error_log /var/log/nginx/{{ app_name }}.log;
location / {
include proxy_params;
proxy_redirect off;
proxy_pass http://localhost:9000;
}
}

239
templates/sentry.conf.j2 Normal file
View file

@ -0,0 +1,239 @@
# {{ ansible_managed }} {{ ansible_date_time.time }} {{ ansible_date_time.date }}
#
# This file is just Python, with a touch of Django which means
# you can inherit and tweak settings to your hearts content.
from sentry.conf.server import * # NOQA
DATABASES = {
"default": {
"ENGINE": "sentry.db.postgres",
"NAME": "{{ postgres_db }}",
"USER": "{{ postgres_user }}",
"PASSWORD": "{{ postgres_password }}",
"HOST": "{{ postgres_host }}",
"PORT": "{{ postgres_port }}",
}
}
# You should not change this setting after your database has been created
# unless you have altered all schemas first
SENTRY_USE_BIG_INTS = True
# If you're expecting any kind of real traffic on Sentry, we highly recommend
# configuring the CACHES and Redis settings
###########
# General #
###########
# Instruct Sentry that this install intends to be run by a single organization
# and thus various UI optimizations should be enabled.
SENTRY_SINGLE_ORGANIZATION = True
SENTRY_OPTIONS["system.event-retention-days"] = int(
env('SENTRY_EVENT_RETENTION_DAYS', '90')
)
#########
# Redis #
#########
# Generic Redis configuration used as defaults for various things including:
# Buffers, Quotas, TSDB
SENTRY_OPTIONS["redis.clusters"] = {
"default": {
"hosts": {0: {"host": "redis", "password": "", "port": "6379", "db": "0"}}
}
}
#########
# Queue #
#########
# See https://docs.getsentry.com/on-premise/server/queue/ for more
# information on configuring your queue broker and workers. Sentry relies
# on a Python framework called Celery to manage queues.
rabbitmq_host = None
if rabbitmq_host:
BROKER_URL = "amqp://{username}:{password}@{host}/{vhost}".format(
username="guest", password="guest", host=rabbitmq_host, vhost="/"
)
else:
BROKER_URL = "redis://:{password}@{host}:{port}/{db}".format(
**SENTRY_OPTIONS["redis.clusters"]["default"]["hosts"][0]
)
#########
# Cache #
#########
# Sentry currently utilizes two separate mechanisms. While CACHES is not a
# requirement, it will optimize several high throughput patterns.
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
"LOCATION": ["memcached:11211"],
"TIMEOUT": 3600,
}
}
# A primary cache is required for things such as processing events
SENTRY_CACHE = "sentry.cache.redis.RedisCache"
DEFAULT_KAFKA_OPTIONS = {
"bootstrap.servers": "kafka:9092",
"message.max.bytes": 50000000,
"socket.timeout.ms": 1000,
}
SENTRY_EVENTSTREAM = "sentry.eventstream.kafka.KafkaEventStream"
SENTRY_EVENTSTREAM_OPTIONS = {"producer_configuration": DEFAULT_KAFKA_OPTIONS}
KAFKA_CLUSTERS["default"] = DEFAULT_KAFKA_OPTIONS
###############
# Rate Limits #
###############
# Rate limits apply to notification handlers and are enforced per-project
# automatically.
SENTRY_RATELIMITER = "sentry.ratelimits.redis.RedisRateLimiter"
##################
# Update Buffers #
##################
# Buffers (combined with queueing) act as an intermediate layer between the
# database and the storage API. They will greatly improve efficiency on large
# numbers of the same events being sent to the API in a short amount of time.
# (read: if you send any kind of real data to Sentry, you should enable buffers)
SENTRY_BUFFER = "sentry.buffer.redis.RedisBuffer"
##########
# Quotas #
##########
# Quotas allow you to rate limit individual projects or the Sentry install as
# a whole.
SENTRY_QUOTAS = "sentry.quotas.redis.RedisQuota"
########
# TSDB #
########
# The TSDB is used for building charts as well as making things like per-rate
# alerts possible.
SENTRY_TSDB = "sentry.tsdb.redissnuba.RedisSnubaTSDB"
#########
# SNUBA #
#########
SENTRY_SEARCH = "sentry.search.snuba.EventsDatasetSnubaSearchBackend"
SENTRY_SEARCH_OPTIONS = {}
SENTRY_TAGSTORE_OPTIONS = {}
###########
# Digests #
###########
# The digest backend powers notification summaries.
SENTRY_DIGESTS = "sentry.digests.backends.redis.RedisBackend"
##############
# Web Server #
##############
SENTRY_WEB_HOST = "0.0.0.0"
SENTRY_WEB_PORT = 9000
SENTRY_WEB_OPTIONS = {
# These ase for proper HTTP/1.1 support from uWSGI
# Without these it doesn't do keep-alives causing
# issues with Relay's direct requests.
"http-keepalive": True,
"http-chunked-input": True,
# the number of web workers
'workers': 3,
# Turn off memory reporting
"memory-report": False,
# Some stuff so uwsgi will cycle workers sensibly
'max-requests': 100000,
'max-requests-delta': 500,
'max-worker-lifetime': 86400,
# Duplicate options from sentry default just so we don't get
# bit by sentry changing a default value that we depend on.
'thunder-lock': True,
'log-x-forwarded-for': False,
'buffer-size': 32768,
'limit-post': 209715200,
'disable-logging': True,
'reload-on-rss': 600,
'ignore-sigpipe': True,
'ignore-write-errors': True,
'disable-write-exception': True,
}
###########
# SSL/TLS #
###########
# If you're using a reverse SSL proxy, you should enable the X-Forwarded-Proto
# header and enable the settings below
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SOCIAL_AUTH_REDIRECT_IS_HTTPS = True
# End of SSL/TLS settings
############
# Features #
############
SENTRY_FEATURES["projects:sample-events"] = False
SENTRY_FEATURES.update(
{
feature: True
for feature in (
"organizations:discover",
"organizations:events",
"organizations:global-views",
"organizations:integrations-issue-basic",
"organizations:integrations-issue-sync",
"organizations:invite-members",
"organizations:sso-basic",
"organizations:sso-rippling",
"organizations:sso-saml2",
"projects:custom-inbound-filters",
"projects:data-forwarding",
"projects:discard-groups",
"projects:plugins",
"projects:rate-limits",
"projects:servicehooks",
)
}
)
######################
# GitHub Integration #
######################
GITHUB_EXTENDED_PERMISSIONS = ['repo']
#########################
# Bitbucket Integration #
########################
# BITBUCKET_CONSUMER_KEY = 'YOUR_BITBUCKET_CONSUMER_KEY'
# BITBUCKET_CONSUMER_SECRET = 'YOUR_BITBUCKET_CONSUMER_SECRET'

106
templates/sentry.config.j2 Normal file
View file

@ -0,0 +1,106 @@
# {{ ansible_managed }} {{ ansible_date_time.time }} {{ ansible_date_time.date }}
#
# While a lot of configuration in Sentry can be changed via the UI, for all
# new-style config (as of 8.0) you can also declare values here in this file
# to enforce defaults or to ensure they cannot be changed via the UI. For more
# information see the Sentry documentation.
###############
# Mail Server #
###############
# mail.backend: 'smtp' # Use dummy if you want to disable email entirely
mail.host: 'smtp'
# mail.port: 25
# mail.username: ''
# mail.password: ''
# mail.use-tls: false
# The email address to send on behalf of
# mail.from: 'root@localhost'
# If you'd like to configure email replies, enable this.
# mail.enable-replies: true
# When email-replies are enabled, this value is used in the Reply-To header
# mail.reply-hostname: ''
# If you're using mailgun for inbound mail, set your API key and configure a
# route to forward to /api/hooks/mailgun/inbound/
# Also don't forget to set `mail.enable-replies: true` above.
# mail.mailgun-api-key: ''
###################
# System Settings #
###################
# The URL prefix in which Sentry is accessible. This will be used both for referencing
# URLs in the UI, as well as in outbound notifications. This only works for scheme, hostname and port.
system.url-prefix: "{{ app_url }}"
# If this file ever becomes compromised, it's important to generate a new key.
# Changing this value will result in all current sessions being invalidated.
# A new key can be generated with `$ sentry config generate-secret-key`
system.secret-key: '{{ app_key }}'
# The ``redis.clusters`` setting is used, unsurprisingly, to configure Redis
# clusters. These clusters can be then referred to by name when configuring
# backends such as the cache, digests, or TSDB backend.
# redis.clusters:
# default:
# hosts:
# 0:
# host: 127.0.0.1
# port: 6379
################
# File storage #
################
# Uploaded media uses these `filestore` settings. The available
# backends are either `filesystem` or `s3`.
filestore.backend: 'filesystem'
filestore.options:
location: '/data/files'
dsym.cache-path: '/data/dsym-cache'
releasefile.cache-path: '/data/releasefile-cache'
# filestore.backend: 's3'
# filestore.options:
# access_key: 'AKIXXXXXX'
# secret_key: 'XXXXXXX'
# bucket_name: 's3-bucket-name'
system.internal-url-prefix: 'http://web:9000'
symbolicator.enabled: true
symbolicator.options:
url: "http://symbolicator:3021"
transaction-events.force-disable-internal-project: true
######################
# GitHub Integration #
######################
# github-app.id: GITHUB_APP_ID
# github-app.name: 'GITHUB_APP_NAME'
# github-app.webhook-secret: 'GITHUB_WEBHOOK_SECRET' # Use only if configured in GitHub
# github-app.client-id: 'GITHUB_CLIENT_ID'
# github-app.client-secret: 'GITHUB_CLIENT_SECRET'
# github-app.private-key: |
# -----BEGIN RSA PRIVATE KEY-----
# privatekeyprivatekeyprivatekeyprivatekey
# privatekeyprivatekeyprivatekeyprivatekey
# privatekeyprivatekeyprivatekeyprivatekey
# privatekeyprivatekeyprivatekeyprivatekey
# privatekeyprivatekeyprivatekeyprivatekey
# -----END RSA PRIVATE KEY-----
#####################
# Slack Integration #
#####################
# Refer to https://forum.sentry.io/t/how-to-configure-slack-in-your-on-prem-sentry/3463 for setup instructions.
# slack.client-id: <'client id'>
# slack.client-secret: <client secret>
# slack.verification-token: <verification token>

View file

@ -0,0 +1,17 @@
# {{ ansible_managed }} {{ ansible_date_time.time }} {{ ansible_date_time.date }}
#
[Unit]
Description=Sentry
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
User={{ app_user }}
ExecStart=/usr/local/bin/docker-compose up --detach
ExecStop=/usr/local/bin/docker-compose down
WorkingDirectory={{ app_dir }}
[Install]
WantedBy=multi-user.target

3
templates/sudoers.j2 Normal file
View file

@ -0,0 +1,3 @@
# {{ ansible_managed }} {{ ansible_date_time.time }} {{ ansible_date_time.date }}
#
ansible ALL = (sentry:sentry) NOPASSWD: ALL

17
vars/main.yml Normal file
View file

@ -0,0 +1,17 @@
default_user: 'sonny'
app_name: 'sentry'
app_dir: '/srv/sites/sentry'
app_url: 'https://sentry.fudiggity.nl'
app_repository: 'https://github.com/getsentry/onpremise.git'
app_branch: '20.7.2'
app_user: 'sentry'
app_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
33666233326139613365306263323464666538303862666561313839646435643866663064356263
6338613833356164393234383834373433373461356535610a333137383364386132643630383163
64386239353139616165633537343933373730646337353830666335303165376366376532653566
6562656564613665300a646364383931343862626334393164323237333061393739643837343331
39646537356434303065633532353332653434316465656561343239616366323163633432646237
31643430363265616263333930373338343034626666313233333730333962313236366337333030
323730396534306339316161366564373962

6
vars/network.yml Normal file
View file

@ -0,0 +1,6 @@
hostname: 'sentry.fudiggity.nl'
host_interface: 'en*'
host_ip: '192.168.178.73'
host_subnet: '24'
host_gateway: '192.168.178.1'
host_dns: '192.168.178.1'

12
vars/postgres.yml Normal file
View file

@ -0,0 +1,12 @@
postgres_host: '192.168.178.165'
postgres_port: '5432'
postgres_db: 'sentry'
postgres_user: 'sentry'
postgres_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
62306238313361643131646665646161336162626464393839353238363861376462663936666239
3166653966303132393563653832653635623131393536640a653037306539666261346232633930
34656431386531303234316137396436653635393061393934393839663032386638633264326133
6564366362326462640a323835633561363433393435376434306535636339646662343234356530
61656162663462616538313835343665333661303963653635346666323933663761376335373832
3761303331613539623761626535336330353836373838363963