mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-29 15:06:26 +02:00
Huge role refactoring/cleanup. Other commits will propably follow. Because some bugs will exist. Still important for longrun and also for auto docs/help/slideshow generation
This commit is contained in:
7
roles/web-app-snipe-it/Administration.md
Normal file
7
roles/web-app-snipe-it/Administration.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Administration 🛠️
|
||||
Clear and restart the application:
|
||||
```bash
|
||||
docker-compose exec application php artisan config:clear
|
||||
docker-compose exec application php artisan cache:clear
|
||||
docker-compose restart application
|
||||
```
|
40
roles/web-app-snipe-it/README.md
Normal file
40
roles/web-app-snipe-it/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Snipe‑IT
|
||||
|
||||
## Description
|
||||
|
||||
Snipe‑IT is an open‑source asset management system designed to streamline hardware and software inventory tracking. This deployment provides an automated, containerized solution using Docker Compose, centralized MariaDB database integration, and secure, configurable environment settings—including robust SMTP email support and pending SAML authentication enhancements.
|
||||
|
||||
## Overview
|
||||
|
||||
This Docker deployment uses Ansible automation to set up Snipe‑IT along with necessary services such as a MariaDB database, an optional OAuth2 proxy for additional security, and a reverse proxy configuration. The system is built for reliable asset management in various environments.
|
||||
|
||||
## Features
|
||||
|
||||
- **Automated Deployment:**
|
||||
Launch Snipe‑IT quickly with Docker Compose and Ansible automation for a production‑ready platform.
|
||||
|
||||
- **Centralized Database Support:**
|
||||
Leverage MariaDB for secure and reliable data storage.
|
||||
|
||||
- **Configurable SMTP Settings:**
|
||||
Manage email notifications and alerts with customizable SMTP configurations.
|
||||
|
||||
- **Optional SAML Authentication:**
|
||||
Prepare for enhanced, standards‑based authentication (integration pending).
|
||||
|
||||
- **Redis Caching:**
|
||||
Improve application performance with built‑in Redis caching support.
|
||||
|
||||
## Other Resources
|
||||
|
||||
- [Snipe‑IT Official Documentation](https://snipe-it.readme.io/docs/ldap-sync-login)
|
||||
- [SAML Setup Instructions](https://snipe-it.readme.io/docs/saml)
|
||||
- [Mattermost SSO Integration Guide](https://docs.mattermost.com/onboard/sso-saml-keycloak.html)
|
||||
- [Additional GitHub Issues and Discussions](https://github.com/snipe/snipe-it/issues)
|
||||
|
||||
## Credits
|
||||
|
||||
Developed and maintained by **Kevin Veen-Birkenbach**.
|
||||
Learn more at [veen.world](https://veen.world)
|
||||
Part of the [CyMaIS Project](https://github.com/kevinveenbirkenbach/cymais)
|
||||
License: [CyMaIS NonCommercial License (CNCL)](https://s.veen.world/cncl)
|
34
roles/web-app-snipe-it/meta/main.yml
Normal file
34
roles/web-app-snipe-it/meta/main.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
galaxy_info:
|
||||
author: "Kevin Veen-Birkenbach"
|
||||
description: "Snipe‑IT is an open‑source asset management system providing a containerized deployment with centralized MariaDB integration, configurable SMTP settings, and pending SAML authentication enhancements for secure asset tracking and management."
|
||||
license: "CyMaIS NonCommercial License (CNCL)"
|
||||
license_url: "https://s.veen.world/cncl"
|
||||
company: |
|
||||
Kevin Veen-Birkenbach
|
||||
Consulting & Coaching Solutions
|
||||
https://www.veen.world
|
||||
min_ansible_version: "2.9"
|
||||
platforms:
|
||||
- name: Linux
|
||||
versions:
|
||||
- all
|
||||
galaxy_tags:
|
||||
- snipe-it
|
||||
- asset-management
|
||||
- docker
|
||||
- mariadb
|
||||
- smtp
|
||||
- saml
|
||||
- automation
|
||||
repository: "https://s.veen.world/cymais"
|
||||
issue_tracker_url: "https://s.veen.world/cymaisissues"
|
||||
documentation: "https://s.veen.world/cymais"
|
||||
logo:
|
||||
class: "fa-solid fa-box"
|
||||
run_after:
|
||||
- web-app-matomo
|
||||
- web-app-keycloak
|
||||
- web-app-mailu
|
||||
dependencies: []
|
||||
|
5
roles/web-app-snipe-it/meta/schema.yml
Normal file
5
roles/web-app-snipe-it/meta/schema.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
credentials:
|
||||
app_key:
|
||||
description: "Generic 32-byte base64 key with base64: prefix"
|
||||
algorithm: base64_prefixed_32
|
||||
validation: '^base64:[A-Za-z0-9+/]{43}=$'
|
106
roles/web-app-snipe-it/tasks/ldap.yml
Normal file
106
roles/web-app-snipe-it/tasks/ldap.yml
Normal file
@@ -0,0 +1,106 @@
|
||||
# @See https://raw.githubusercontent.com/snipe/snipe-it/master/app/Models/Setting.php
|
||||
---
|
||||
- name: "Wait until the Snipe-IT Login is available"
|
||||
uri:
|
||||
url: "{{ snipe_it_url }}/login"
|
||||
method: GET
|
||||
return_content: no
|
||||
status_code: 200
|
||||
register: snipeit_admin_check
|
||||
retries: 30
|
||||
delay: 5
|
||||
until: snipeit_admin_check.status == 200
|
||||
when: not ( applications | is_feature_enabled('oauth2', application_id))
|
||||
|
||||
- name: "Debug: show APP_KEY in container shell"
|
||||
shell: |
|
||||
docker-compose exec -T \
|
||||
-u www-data \
|
||||
-e XDG_CONFIG_HOME=/tmp \
|
||||
-e APP_KEY='{{ applications[application_id].credentials.app_key }}' \
|
||||
application \
|
||||
sh -c 'echo "SHELL sees APP_KEY=$APP_KEY"'
|
||||
args:
|
||||
chdir: "/opt/docker/snipe-it/"
|
||||
|
||||
- name: "Debug: show APP_KEY in container shell"
|
||||
shell: |
|
||||
docker-compose exec -T -u www-data \
|
||||
-e XDG_CONFIG_HOME=/tmp \
|
||||
-e APP_KEY="{{ applications[application_id].credentials.app_key }}" \
|
||||
application \
|
||||
php artisan tinker --execute="echo 'CONFIG app.key: ' . config('app.key') . PHP_EOL;"
|
||||
args:
|
||||
chdir: "/opt/docker/snipe-it/"
|
||||
|
||||
- name: "Set all LDAP settings via Laravel Setting model (inside container as www-data)"
|
||||
shell: |
|
||||
docker-compose exec -T \
|
||||
-e APP_KEY='{{ applications[application_id].credentials.app_key }}' \
|
||||
-e XDG_CONFIG_HOME=/tmp \
|
||||
-u www-data application \
|
||||
sh -c 'php artisan tinker << "EOF"
|
||||
$s = \App\Models\Setting::getSettings();
|
||||
$s->ldap_enabled = 1;
|
||||
$s->ldap_server = "{{ ldap.server.uri }}";
|
||||
$s->ldap_port = {{ ldap.server.port }};
|
||||
$s->ldap_uname = "{{ ldap.dn.administrator.data }}";
|
||||
$s->ldap_basedn = "{{ ldap.dn.ou.users }}";
|
||||
$s->ldap_filter = "&(objectClass=inetOrgPerson)";
|
||||
$s->ldap_username_field = "{{ ldap.user.attributes.id }}";
|
||||
$s->ldap_fname_field = "{{ ldap.user.attributes.firstname }}";
|
||||
$s->ldap_lname_field = "{{ ldap.user.attributes.surname }}";
|
||||
$s->ldap_auth_filter_query = "uid=";
|
||||
$s->ldap_version = 3;
|
||||
$s->ldap_pw_sync = 0;
|
||||
$s->is_ad = 0;
|
||||
$s->ad_domain = "";
|
||||
$s->ldap_default_group = "";
|
||||
$s->ldap_email = "{{ ldap.user.attributes.mail }}";
|
||||
$s->custom_forgot_pass_url = "{{ oidc.client.reset_credentials }}";
|
||||
$s->save();
|
||||
EOF'
|
||||
args:
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
register: ldap_tinker
|
||||
failed_when: >
|
||||
ldap_tinker.stdout_lines is not defined
|
||||
or ldap_tinker.stdout_lines[0] != '= true'
|
||||
changed_when: >
|
||||
ldap_tinker.stdout_lines is defined
|
||||
and ldap_tinker.stdout_lines[0] == '= true'
|
||||
notify: docker compose up
|
||||
|
||||
- name: Encrypt & save LDAP bind password via Crypt + DB façade
|
||||
shell: |
|
||||
docker-compose exec -T \
|
||||
-u www-data \
|
||||
-e APP_KEY="{{ applications[application_id].credentials.app_key }}" \
|
||||
-e XDG_CONFIG_HOME=/tmp \
|
||||
application \
|
||||
php artisan tinker --execute="
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/* encrypt the clear-text password */
|
||||
\$encrypted = Crypt::encrypt('{{ ldap.bind_credential }}');
|
||||
|
||||
/* write it straight into settings.ldap_pword */
|
||||
/* update the one and only row in `settings` */
|
||||
DB::table('settings')->update([
|
||||
'ldap_pword' => \$encrypted
|
||||
]);
|
||||
echo 'Stored: ' . \$encrypted . PHP_EOL;
|
||||
"
|
||||
args:
|
||||
chdir: "/opt/docker/snipe-it/"
|
||||
register: ldap_encrypt
|
||||
failed_when: ldap_encrypt.rc != 0
|
||||
|
||||
- name: "Clear Laravel config & cache (inside container as www-data)"
|
||||
shell: |
|
||||
docker-compose exec -T -u www-data application php artisan config:clear
|
||||
docker-compose exec -T -u www-data application php artisan cache:clear
|
||||
args:
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
notify: docker compose up
|
16
roles/web-app-snipe-it/tasks/main.yml
Normal file
16
roles/web-app-snipe-it/tasks/main.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: "include service-rdbms-central"
|
||||
include_role:
|
||||
name: service-rdbms-central
|
||||
|
||||
- name: "include role webserver-proxy-domain for {{application_id}}"
|
||||
include_role:
|
||||
name: webserver-proxy-domain
|
||||
vars:
|
||||
domain: "{{ domains | get_domain(application_id) }}"
|
||||
http_port: "{{ ports.localhost.http[application_id] }}"
|
||||
|
||||
|
||||
- name: "Configure Snipe-IT LDAP settings"
|
||||
import_tasks: ldap.yml
|
||||
when: applications | is_feature_enabled('ldap',application_id)
|
18
roles/web-app-snipe-it/templates/docker-compose.yml.j2
Normal file
18
roles/web-app-snipe-it/templates/docker-compose.yml.j2
Normal file
@@ -0,0 +1,18 @@
|
||||
{% include 'roles/docker-compose/templates/base.yml.j2' %}
|
||||
|
||||
application:
|
||||
{% set container_port = 80 %}
|
||||
image: grokability/snipe-it:{{applications[application_id].version}}
|
||||
{% include 'roles/docker-container/templates/base.yml.j2' %}
|
||||
volumes:
|
||||
- data:/var/lib/snipeit
|
||||
ports:
|
||||
- "127.0.0.1:{{ports.localhost.http[application_id]}}:{{ container_port }}"
|
||||
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
|
||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||
{% include 'roles/docker-container/templates/healthcheck/tcp.yml.j2' %}
|
||||
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
|
||||
redis:
|
||||
data:
|
||||
|
||||
{% include 'roles/docker-compose/templates/networks.yml.j2' %}
|
167
roles/web-app-snipe-it/templates/env.j2
Normal file
167
roles/web-app-snipe-it/templates/env.j2
Normal file
@@ -0,0 +1,167 @@
|
||||
# --------------------------------------------
|
||||
# REQUIRED: BASIC APP SETTINGS
|
||||
# --------------------------------------------
|
||||
APP_ENV={{ CYMAIS_ENVIRONMENT | lower }}
|
||||
APP_DEBUG={{enable_debug | string | lower }}
|
||||
APP_KEY={{ applications[application_id].credentials.app_key}}
|
||||
APP_URL={{ snipe_it_url }}
|
||||
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones - TZ identifier
|
||||
APP_TIMEZONE='{{ HOST_TIMEZONE }}'
|
||||
APP_LOCALE={{ HOST_LL }}
|
||||
MAX_RESULTS=500
|
||||
|
||||
# --------------------------------------------
|
||||
# REQUIRED: UPLOADED FILE STORAGE SETTINGS
|
||||
# --------------------------------------------
|
||||
PRIVATE_FILESYSTEM_DISK=local
|
||||
PUBLIC_FILESYSTEM_DISK=local_public
|
||||
|
||||
# --------------------------------------------
|
||||
# REQUIRED: DATABASE SETTINGS
|
||||
# --------------------------------------------
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST={{database_host}}
|
||||
DB_PORT={{database_port}}
|
||||
DB_DATABASE={{database_name}}
|
||||
DB_USERNAME={{database_username}}
|
||||
DB_PASSWORD={{database_password}}
|
||||
|
||||
{% if not applications | is_feature_enabled('central_database',application_id) %}
|
||||
MYSQL_ROOT_PASSWORD={{database_password}}
|
||||
DB_PREFIX=null
|
||||
DB_DUMP_PATH='/usr/bin'
|
||||
DB_CHARSET=utf8mb4
|
||||
DB_COLLATION=utf8mb4_unicode_ci
|
||||
{% endif %}
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: SSL DATABASE SETTINGS
|
||||
# --------------------------------------------
|
||||
DB_SSL=false
|
||||
DB_SSL_IS_PAAS=false
|
||||
DB_SSL_KEY_PATH=null
|
||||
DB_SSL_CERT_PATH=null
|
||||
DB_SSL_CA_PATH=null
|
||||
DB_SSL_CIPHER=null
|
||||
DB_SSL_VERIFY_SERVER=null
|
||||
|
||||
# --------------------------------------------
|
||||
# REQUIRED: OUTGOING MAIL SERVER SETTINGS
|
||||
# --------------------------------------------
|
||||
MAIL_MAILER = smtp
|
||||
MAIL_HOST = {{system_email.host}}
|
||||
MAIL_PORT = {{system_email.port}}
|
||||
MAIL_USERNAME = {{ users['no-reply'].email }}
|
||||
MAIL_PASSWORD = {{ users['no-reply'].mailu_token }}
|
||||
MAIL_TLS_VERIFY_PEER = {{ system_email.tls | capitalize }}
|
||||
MAIL_FROM_ADDR = {{ users['no-reply'].email }}
|
||||
MAIL_FROM_NAME = {{ service_provider.company.titel }} - Snipe-IT
|
||||
MAIL_REPLYTO_ADDR = {{ users['no-reply'].email }}
|
||||
MAIL_REPLYTO_NAME = {{ service_provider.company.titel }} - Snipe-IT
|
||||
MAIL_AUTO_EMBED_METHOD = 'attachment'
|
||||
|
||||
# --------------------------------------------
|
||||
# REQUIRED: DATA PROTECTION
|
||||
# --------------------------------------------
|
||||
ALLOW_BACKUP_DELETE=false
|
||||
ALLOW_DATA_PURGE=false
|
||||
|
||||
# --------------------------------------------
|
||||
# REQUIRED: IMAGE LIBRARY
|
||||
# This should be gd or imagick
|
||||
# --------------------------------------------
|
||||
IMAGE_LIB=gd
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: BACKUP SETTINGS
|
||||
# --------------------------------------------
|
||||
MAIL_BACKUP_NOTIFICATION_DRIVER=null
|
||||
MAIL_BACKUP_NOTIFICATION_ADDRESS=null
|
||||
BACKUP_ENV=true
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: SESSION SETTINGS
|
||||
# --------------------------------------------
|
||||
SESSION_LIFETIME=12000
|
||||
EXPIRE_ON_CLOSE=false
|
||||
ENCRYPT=false
|
||||
COOKIE_NAME=snipeit_session
|
||||
COOKIE_DOMAIN=null
|
||||
SECURE_COOKIES=true
|
||||
API_TOKEN_EXPIRATION_YEARS=40
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: SECURITY HEADER SETTINGS
|
||||
# --------------------------------------------
|
||||
APP_TRUSTED_PROXIES=**
|
||||
ALLOW_IFRAMING=false
|
||||
REFERRER_POLICY=same-origin
|
||||
ENABLE_CSP=false
|
||||
CORS_ALLOWED_ORIGINS=null
|
||||
ENABLE_HSTS=true # Certificates managed by nginx
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: CACHE SETTINGS
|
||||
# --------------------------------------------
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
QUEUE_DRIVER=sync
|
||||
CACHE_PREFIX=snipeit
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: REDIS SETTINGS
|
||||
# --------------------------------------------
|
||||
REDIS_HOST=redis
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: MEMCACHED SETTINGS
|
||||
# --------------------------------------------
|
||||
MEMCACHED_HOST=null
|
||||
MEMCACHED_PORT=null
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: PUBLIC S3 Settings
|
||||
# --------------------------------------------
|
||||
PUBLIC_AWS_SECRET_ACCESS_KEY=null
|
||||
PUBLIC_AWS_ACCESS_KEY_ID=null
|
||||
PUBLIC_AWS_DEFAULT_REGION=null
|
||||
PUBLIC_AWS_BUCKET=null
|
||||
PUBLIC_AWS_URL=null
|
||||
PUBLIC_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: PRIVATE S3 Settings
|
||||
# --------------------------------------------
|
||||
PRIVATE_AWS_ACCESS_KEY_ID=null
|
||||
PRIVATE_AWS_SECRET_ACCESS_KEY=null
|
||||
PRIVATE_AWS_DEFAULT_REGION=null
|
||||
PRIVATE_AWS_BUCKET=null
|
||||
PRIVATE_AWS_URL=null
|
||||
PRIVATE_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: AWS Settings
|
||||
# --------------------------------------------
|
||||
AWS_ACCESS_KEY_ID=null
|
||||
AWS_SECRET_ACCESS_KEY=null
|
||||
AWS_DEFAULT_REGION=null
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: LOGIN THROTTLING
|
||||
# --------------------------------------------
|
||||
LOGIN_MAX_ATTEMPTS=5
|
||||
LOGIN_LOCKOUT_DURATION=60
|
||||
RESET_PASSWORD_LINK_EXPIRES=900
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: MISC
|
||||
# --------------------------------------------
|
||||
LOG_CHANNEL=stderr
|
||||
LOG_MAX_DAYS=10
|
||||
APP_LOCKED=false
|
||||
APP_CIPHER=AES-256-CBC
|
||||
APP_FORCE_TLS=true
|
||||
GOOGLE_MAPS_API=
|
||||
LDAP_MEM_LIM=500M
|
||||
LDAP_TIME_LIM=600
|
35
roles/web-app-snipe-it/vars/configuration.yml
Normal file
35
roles/web-app-snipe-it/vars/configuration.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
version: "latest"
|
||||
features:
|
||||
matomo: true
|
||||
css: false
|
||||
portfolio_iframe: true
|
||||
central_database: true
|
||||
ldap: true
|
||||
oauth2: true
|
||||
domains:
|
||||
canonical:
|
||||
- "inventory.{{ primary_domain }}"
|
||||
csp:
|
||||
flags:
|
||||
script-src:
|
||||
unsafe-inline: true
|
||||
unsafe-eval: true
|
||||
script-src-elem:
|
||||
unsafe-inline: true
|
||||
style-src:
|
||||
unsafe-inline: true
|
||||
whitelist:
|
||||
font-src:
|
||||
- "data:"
|
||||
oauth2_proxy:
|
||||
application: "application"
|
||||
port: "80"
|
||||
acl:
|
||||
blacklist:
|
||||
- "/login"
|
||||
docker:
|
||||
services:
|
||||
redis:
|
||||
enabled: true
|
||||
database:
|
||||
enabled: true
|
4
roles/web-app-snipe-it/vars/main.yml
Normal file
4
roles/web-app-snipe-it/vars/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
application_id: "snipe-it"
|
||||
database_password: "{{ applications[application_id].credentials.database_password }}"
|
||||
database_type: "mariadb"
|
||||
snipe_it_url: "{{ domains | get_url(application_id, web_protocol) }}"
|
Reference in New Issue
Block a user