From b47cdf4e71c5df9d756df89ff8e447f14fafb808 Mon Sep 17 00:00:00 2001 From: "Trez.One" Date: Fri, 17 Jan 2025 18:48:08 -0500 Subject: [PATCH] . --- .gitignore | 2 +- ansible/ansible-inventory | 15 + ansible/app-configs/crowdsec_acquis.yaml.j2 | 15 + ansible/app-configs/crowdsec_profiles.yaml.j2 | 17 + .../gitea-sonarqube-bot_config.yaml.j2 | 81 +++ ansible/app-configs/gitea_app.ini.j2 | 125 +++++ .../app-configs/grafana_alloy_config.alloy | 404 +++++++++++++++ .../grafana_alloy_endpoints.json.j2 | 34 ++ .../app-configs/grafana_tempo_tempo.yaml.j2 | 54 ++ ansible/app-configs/homepage_settings.yaml.j2 | 60 +++ .../invoice-ninja_invoice-ninja.env.j2 | 52 ++ .../app-configs/komodo_core.config.toml.j2 | 477 ++++++++++++++++++ ansible/app-configs/lidarr_config.xml.j2 | 21 + .../lidify_settings_config.json.j2 | 25 + .../multi-scrobbler_config.json.j2 | 63 +++ ansible/app-configs/postal_postal.yml.j2 | 59 +++ ansible/app-configs/prowlarr_config.xml.j2 | 21 + ansible/app-configs/radarr_config.xml.j2 | 21 + ansible/app-configs/readarr_config.xml.j2 | 21 + ansible/app-configs/sonarr_config.xml.j2 | 22 + ansible/collections/requirements.yml | 7 + ansible/group_vars/all.yml | 14 + ansible/host_vars.yml | 12 + ansible/ssh_pass.yml | 7 + 24 files changed, 1628 insertions(+), 1 deletion(-) create mode 100644 ansible/ansible-inventory create mode 100644 ansible/app-configs/crowdsec_acquis.yaml.j2 create mode 100644 ansible/app-configs/crowdsec_profiles.yaml.j2 create mode 100644 ansible/app-configs/gitea-sonarqube-bot_config.yaml.j2 create mode 100644 ansible/app-configs/gitea_app.ini.j2 create mode 100644 ansible/app-configs/grafana_alloy_config.alloy create mode 100644 ansible/app-configs/grafana_alloy_endpoints.json.j2 create mode 100644 ansible/app-configs/grafana_tempo_tempo.yaml.j2 create mode 100644 ansible/app-configs/homepage_settings.yaml.j2 create mode 100644 ansible/app-configs/invoice-ninja_invoice-ninja.env.j2 create mode 100644 ansible/app-configs/komodo_core.config.toml.j2 create mode 100644 ansible/app-configs/lidarr_config.xml.j2 create mode 100644 ansible/app-configs/lidify_settings_config.json.j2 create mode 100644 ansible/app-configs/multi-scrobbler_config.json.j2 create mode 100644 ansible/app-configs/postal_postal.yml.j2 create mode 100644 ansible/app-configs/prowlarr_config.xml.j2 create mode 100644 ansible/app-configs/radarr_config.xml.j2 create mode 100644 ansible/app-configs/readarr_config.xml.j2 create mode 100644 ansible/app-configs/sonarr_config.xml.j2 create mode 100644 ansible/collections/requirements.yml create mode 100644 ansible/group_vars/all.yml create mode 100644 ansible/host_vars.yml create mode 100644 ansible/ssh_pass.yml diff --git a/.gitignore b/.gitignore index ca854d2c..38d143ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -ansible/** \ No newline at end of file +**/.cache.ggshield diff --git a/ansible/ansible-inventory b/ansible/ansible-inventory new file mode 100644 index 00000000..ddb7dd78 --- /dev/null +++ b/ansible/ansible-inventory @@ -0,0 +1,15 @@ +all: + hosts: + rinoa: + ansible_host: 192.168.1.254 + ansible_python_interpreter: /usr/bin/python3 + ansible_ssh_port: 22 + ansible_ssh_user: charish + ansible_ssh_pass: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 38346631616139316365316566386362396661323163306339303635646331373061323531626431 + 3435373031363739356261656239633835393963636663370a613166653463656337666366633639 + 37373637326633363430633336646165343764303063663636313835326130663532323037663331 + 6332353339656134370a353435396532663932313535646636333262353238386331313764633635 + 63383065623930653134666261353439366535646661383434386261393232373432353937636535 + 3432336137393737643735346665303832653630316439333565 \ No newline at end of file diff --git a/ansible/app-configs/crowdsec_acquis.yaml.j2 b/ansible/app-configs/crowdsec_acquis.yaml.j2 new file mode 100644 index 00000000..2830970b --- /dev/null +++ b/ansible/app-configs/crowdsec_acquis.yaml.j2 @@ -0,0 +1,15 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + + +source: journalctl +journalctl_filter: + - "--directory=/var/log/host/" +labels: + type: syslog +--- +filenames: + - /var/log/swag/* +labels: + type: nginx +--- diff --git a/ansible/app-configs/crowdsec_profiles.yaml.j2 b/ansible/app-configs/crowdsec_profiles.yaml.j2 new file mode 100644 index 00000000..0dfb52c6 --- /dev/null +++ b/ansible/app-configs/crowdsec_profiles.yaml.j2 @@ -0,0 +1,17 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +name: default_ip_remediation +#debug: true +filters: + - Alert.Remediation == true && Alert.GetScope() == "Ip" +decisions: + - type: ban + duration: 4h +#duration_expr: Sprintf('%dh', (GetDecisionsCount(Alert.GetValue()) + 1) * 4) +# notifications: +# - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this. +# - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this. +# - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this. +# - email_default # Set the required email parameters in /etc/crowdsec/notifications/email.yaml before enabling this. +on_success: break \ No newline at end of file diff --git a/ansible/app-configs/gitea-sonarqube-bot_config.yaml.j2 b/ansible/app-configs/gitea-sonarqube-bot_config.yaml.j2 new file mode 100644 index 00000000..90b9fb69 --- /dev/null +++ b/ansible/app-configs/gitea-sonarqube-bot_config.yaml.j2 @@ -0,0 +1,81 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +# Gitea related configuration. Necessary for adding/updating comments on repository pull requests +gitea: + # Endpoint of your Gitea instance. Must be expandable by '/api/v1' to form the API base path as shown in Swagger UI. + url: https://git.trez.wtf + + # Created access token for the user that shall be used as bot account. + # User needs "Read project" permissions with access to "Pull Requests" + token: + value: "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['GITEA_SONARQUBE_BOT_GITEA_TOKEN'] }}" + # # or path to file containing the plain text secret + # file: /path/to/gitea/token + + # If the sent webhook has a signature header, the bot validates the request payload. If the value does not match, the + # request will be ignored. + # The bot looks for `X-Gitea-Signature` header containing the sha256 hmac hash of the plain text secret. If the header + # exists and no webhookSecret is defined here, the bot will ignore the request, because it cannot be validated. + webhook: + secret: "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['GITEA_SONARQUBE_BOT_GITEA_WEBHOOK_SECRET'] }}" + # # or path to file containing the plain text secret + # secretFile: /path/to/gitea/webhook/secret + + # Pull Request status check settings. + statusCheck: + # Configure the label/name of the PR status check. + name: "gitea-sonarqube-bot" + +# SonarQube related configuration. Necessary for requesting data from the API and processing the webhook. +sonarqube: + # Endpoint of your SonarQube instance. Must be expandable by '/api' to form the API base path. + url: https://sqube.trez.wtf + + # Created access token for the user that shall be used as bot account. + # User needs "Browse on project" permissions + token: + value: "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['GITEA_SONARQUBE_BOT_SQUBE_TOKEN'] }}" + # # or path to file containing the plain text secret + # file: /path/to/sonarqube/token + + # If the sent webhook has a signature header, the bot validates the request payload. If the value does not match, the + # request will be ignored. + # The bot looks for `X-Sonar-Webhook-HMAC-SHA256` header containing the sha256 hmac hash of the plain text secret. + # If the header exists and no webhookSecret is defined here, the bot will ignore the request, because it cannot be + # validated. + webhook: + secret: "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['GITEA_SONARQUBE_BOT_SQUBE_WEBHOOK_SECRET'] }}" + # # or path to file containing the plain text secret + # secretFile: /path/to/sonarqube/webhook/secret + + # Some useful metrics depend on the edition in use. There are various ones like code_smells, vulnerabilities, bugs, etc. + # By default, the bot will extract "bugs,vulnerabilities,code_smells" + # Setting this option you can extend that default list by your own metrics. + # additionalMetrics: [] + # - "new_security_hotspots" + +# List of project mappings to take care of. Webhooks for other projects will be ignored. +# At least one must be configured. Otherwise, all webhooks (no matter which source) because the bot cannot map on its own. +projects: + - sonarqube: + key: rinoa-docker + # A repository specification contains the owner name and the repository name itself. The owner can be the name of a + # real account or an organization in which the repository is located. + gitea: + owner: Trez.One + name: rinoa-docker + +# Define pull request names from SonarScanner analysis. Default pattern matches the Jenkins Gitea plugin schema. +namingPattern: + # Regular expression that MUST HAVE exactly ONE GROUP that matches the integer part of the PR. + # That integer part is identical to the pull request ID in Gitea. + regex: "^.*$" + + # Valid Go format string. It MUST have one integer placeholder which will be replaced by the pull request ID. + # See: https://pkg.go.dev/fmt#hdr-Printing + template: "%s" + + # Example for integer-only names + # # regex: "^(\\d+)$" + # # template: "%d" diff --git a/ansible/app-configs/gitea_app.ini.j2 b/ansible/app-configs/gitea_app.ini.j2 new file mode 100644 index 00000000..cc3702cf --- /dev/null +++ b/ansible/app-configs/gitea_app.ini.j2 @@ -0,0 +1,125 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +APP_NAME = Gitea: Git with a cup of tea +RUN_MODE = prod +RUN_USER = git +WORK_PATH = /data/gitea + +[repository] +ROOT = /data/git/repositories +DEFAULT_PRIVATE = last +EMABLE_PUSH_CREATE_USER = true + +[repository.local] +LOCAL_COPY_PATH = /data/gitea/tmp/local-repo + +[repository.upload] +TEMP_PATH = /data/gitea/uploads + +[server] +APP_DATA_PATH = /data/gitea +DOMAIN = git.trez.wtf +SSH_DOMAIN = git-ssh.trez.wtf +HTTP_PORT = 3000 +ROOT_URL = https://git.trez.wtf/ +DISABLE_SSH = false +SSH_PORT = 22 +SSH_LISTEN_PORT = 22 +LFS_START_SERVER = true +LFS_JWT_SECRET = {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['GITEA_LFS_JWT_SECRET'] }} +OFFLINE_MODE = true + +[database] +PATH = /data/gitea/gitea.db +DB_TYPE = postgres +HOST = gitea-db:5432 +NAME = gitea +USER = gitea +PASSWD = {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['GITEA_PG_DB_PASSWORD'] }} +LOG_SQL = false +SCHEMA = +SSL_MODE = disable + +[indexer] +ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve +REPO_INDEXER_ENABLED = true +REPO_INDEXER_PATH = indexers/repos.bleve +MAX_FILE_SIZE = 1048576 +REPO_INDEXER_INCLUDE = +REPO_INDEXER_EXCLUDE = resources/bin/** + +[session] +PROVIDER_CONFIG = /data/gitea/sessions +PROVIDER = file + +[picture] +AVATAR_UPLOAD_PATH = /data/gitea/avatars +REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars + +[attachment] +PATH = /data/gitea/attachments + +[log] +MODE = console +LEVEL = info +ROOT_PATH = root + +[security] +INSTALL_LOCK = true +SECRET_KEY = +REVERSE_PROXY_LIMIT = 1 +REVERSE_PROXY_TRUSTED_PROXIES = * +INTERNAL_TOKEN = {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['GITEA_INTERNAL_TOKEN'] }} +PASSWORD_HASH_ALGO = pbkdf2 + +[service] +DISABLE_REGISTRATION = false +REQUIRE_SIGNIN_VIEW = false +REGISTER_EMAIL_CONFIRM = true +ENABLE_NOTIFY_MAIL = true +ALLOW_ONLY_EXTERNAL_REGISTRATION = false +ENABLE_CAPTCHA = true +DEFAULT_KEEP_EMAIL_PRIVATE = true +DEFAULT_ALLOW_CREATE_ORGANIZATION = false +DEFAULT_ENABLE_TIMETRACKING = false +NO_REPLY_ADDRESS = noreply@trez.wtf + +[lfs] +PATH = /data/git/lfs + +[mailer] +PASSWD = {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['POSTAL_SMTP_AUTH_PASSWORD'] }} +PROTOCOL = smtp +ENABLED = true +FROM = '"Gitea" ' +SMTP_PORT = 25 +USER = rinoa/postal-smtp +SMTP_ADDR = postal-smtp +IS_TLS_ENABLED = faLse + +[openid] +ENABLE_OPENID_SIGNIN = true +ENABLE_OPENID_SIGNUP = true + +[cron.update_checker] +ENABLED = false + +[repository.pull-request] +DEFAULT_MERGE_STYLE = merge + +[repository.signing] +DEFAULT_TRUST_MODEL = committer + +[oauth2] +JWT_SECRET = {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['GITEA_OAUTH2_JWT_SECRET'] }} + +[ui] +THEMES = theme-catppuccin-blue-auto.css,theme-catppuccin-sapphire-auto.css,theme-catppuccin-yellow-auto.css,theme-catppuccin-maroon-auto.css,theme-catppuccin-mauve-auto.css,theme-catppuccin-peach-auto.css,theme-catppuccin-teal-auto.css,theme-catppuccin-flamingo-auto.css,theme-catppuccin-lavender-auto.css,theme-catppuccin-pink-auto.css,theme-catppuccin-red-auto.css,theme-catppuccin-rosewater-auto.css,theme-catppuccin-sky-auto.css,theme-catppuccin-green-auto.css + +[actions] +ENABLED = true + +[webhook] +ALLOWED_HOST_LIST = private,104.21.1.234,172.67.152.146 +SKIP_TLS_VERIFY = true diff --git a/ansible/app-configs/grafana_alloy_config.alloy b/ansible/app-configs/grafana_alloy_config.alloy new file mode 100644 index 00000000..a6441e39 --- /dev/null +++ b/ansible/app-configs/grafana_alloy_config.alloy @@ -0,0 +1,404 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Agent globals +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +local.file "endpoints" { + // The endpoints file is used to define the endpoints, credentials and options + // for the Agent export to. + filename = "/etc/alloy/endpoints.json" +} + +discovery.docker "rinoadocker" { + host = env("DOCKER_HOST") +} + +tracing { + write_to = [otelcol.exporter.otlp.tempo.input] +} +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Metrics +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +prometheus.remote_write "mimir" { + endpoint { + url = json_path(local.file.endpoints.content, ".metrics.url")[0] + basic_auth { + username = json_path(local.file.endpoints.content, ".metrics.basicAuth.username")[0] + password = json_path(local.file.endpoints.content, ".metrics.basicAuth.password")[0] + } + } +} + +prometheus.scrape "prometheus" { + targets = [{ + __address__ = "localhost:12345", + }] + forward_to = [prometheus.remote_write.mimir.receiver] + job_name = "prometheus" +} + +prometheus.exporter.unix "rinoa" { + procfs_path = "/host/proc" + sysfs_path = "/host/sys" + rootfs_path = "/rootfs" +} + +prometheus.scrape "rinoa" { + targets = prometheus.exporter.unix.rinoa.targets + forward_to = [prometheus.remote_write.mimir.receiver] + job_name = "rinoa_host" +} + +prometheus.exporter.cadvisor "docker" { + docker_host = env("DOCKER_HOST") + storage_duration = "5m" +} + +prometheus.scrape "docker" { + targets = prometheus.exporter.cadvisor.docker.targets + forward_to = [prometheus.remote_write.mimir.receiver] + job_name = "docker_stats" +} +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Logging +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +loki.write "loki" { + endpoint { + url = json_path(local.file.endpoints.content, ".logs.url")[0] + basic_auth { + username = json_path(local.file.endpoints.content, ".logs.basicAuth.username")[0] + password = json_path(local.file.endpoints.content, ".logs.basicAuth.password")[0] + } + } + external_labels = {} +} + +loki.source.journal "hostjournal" { + forward_to = [loki.write.loki.receiver] + max_age = "24h" + path = "/rootfs/var/log/journal/" + labels = { + job = "host-journal", + } +} + +local.file_match "system" { + path_targets = [{ + __address__ = "localhost", + __path__ = "/rootfs/var/log/*log", + job = "varlogs", + }] +} + +loki.source.file "system" { + targets = local.file_match.system.targets + forward_to = [loki.write.loki.receiver] +} + +loki.source.docker "containers" { + host = env("DOCKER_HOST") + targets = discovery.docker.rinoadocker.targets + forward_to = [loki.write.loki.receiver] + labels = { + job = "containerlogs", + } +} + +loki.process "containers" { + forward_to = [loki.write.loki.receiver] + // stage.docker {} + stage.json { + expressions = { + attrs = "", + output = "log", + stream = "stream", + } + } + + stage.json { + expressions = { + tag = "", + } + source = "attrs" + } + + stage.regex { + expression = "(?P(?:[^|]*[^|])).(?P(?:[^|]*[^|])).(?P(?:[^|]*[^|])).(?P(?:[^|]*[^|]))" + source = "tag" + } + + stage.timestamp { + source = "time" + format = "RFC3339Nano" + } + + stage.labels { + values = { + container_id = null, + container_name = null, + image_id = null, + image_name = null, + stream = null, + tag = null, + } + } + + stage.output { + source = "output" + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Traces +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +beyla.ebpf "rinoadocker" { + open_port = "80-65535" + routes { + unmatched = "heauristic" + } + output { + traces = [ + otelcol.connector.servicegraph.tracemetrics.input, + otelcol.connector.spanmetrics.tracemetrics.input, + otelcol.processor.batch.default.input, + otelcol.connector.spanlogs.autologging.input, + ] + } +} + +prometheus.scrape "beyla" { + targets = beyla.ebpf.rinoadocker.targets + forward_to = [prometheus.remote_write.mimir.receiver] +} + +otelcol.auth.headers "tempo" { + header { + key = "Authorization" + value = join(["Basic ", json_path(local.file.endpoints.content, ".traces.basicAuthToken")[0]], "") + } +} + +otelcol.processor.batch "default" { + // Wait until we've received 16K of data. + send_batch_size = 16384 + send_batch_max_size = 16384 + // Or until 2 seconds have elapsed. + timeout = "2s" + // When the Agent has enough batched data, send it to the OpenTelemetry exporter named 'tempo'. + output { + traces = [otelcol.exporter.otlp.tempo.input] + } +} + +otelcol.exporter.otlp "tempo" { + // Define the client for exporting. + client { + // Authentication block. + auth = otelcol.auth.headers.tempo.handler + + // Send to the locally running Tempo instance, on port 4317 (OTLP gRPC). + endpoint = json_path(local.file.endpoints.content, ".traces.url")[0] + + // Configure TLS settings for communicating with the endpoint. + tls { + // The connection is insecure. + insecure = json_path(local.file.endpoints.content, ".traces.tls.insecure")[0] + // Do not verify TLS certificates when connecting. + insecure_skip_verify = json_path(local.file.endpoints.content, ".traces.tls.insecureSkipVerify")[0] + } + } +} + +otelcol.connector.spanlogs "autologging" { + // We only want to output a line for each root span (ie. every single trace), and not for every + // process or span (outputting a line for every span would be extremely verbose). + spans = false + roots = true + processes = false + // We want to ensure that the following three span attributes are included in the log line, if + // present. + span_attributes = [ "http.method", "http.target", "http.status_code" ] + + // Overrides the default key in the log line to be `traceId`, which is then used by Grafana to + // identify the trace ID for correlation with the Tempo datasource. + overrides { + trace_id_key = "traceId" + } + // Send to the OpenTelemetry Loki exporter. + output { + logs = [otelcol.exporter.loki.autologging.input] + } +} + +// Simply forwards the incoming OpenTelemetry log format out as a Loki log. +// We need this stage to ensure we can then process the logline as a Loki object. +otelcol.exporter.loki "autologging" { + forward_to = [loki.process.autologging.receiver] +} + +// The Loki processor allows us to accept a correctly formatted Loki log and mutate it into +// a set of fields for output. +loki.process "autologging" { + // The JSON stage simply extracts the `body` (the actual logline) from the Loki log, ignoring + // all other fields. + stage.json { + expressions = { "body" = "" } + } + // The output stage takes the body (the main logline) and uses this as the source for the output + // logline. In this case, it essentially turns it into logfmt. + stage.output { + source = "body" + } + + // Finally send the processed logline onto the Loki exporter. + forward_to = [loki.write.autologging.receiver] +} + +// The Loki writer receives a processed Loki log and then writes it to a Loki instance. +loki.write "autologging" { + // Add the `agent` value to the `job` label, so we can identify it as having been generated + // by Grafana Agent when querying. + external_labels = { + job = "agent", + } + + // Output the Loki log to the local Loki instance. + endpoint { + url = json_path(local.file.endpoints.content, ".logs.url")[0] + + // The basic auth credentials for the Loki instance. + basic_auth { + username = json_path(local.file.endpoints.content, ".logs.basicAuth.username")[0] + password = json_path(local.file.endpoints.content, ".logs.basicAuth.password")[0] + } + } +} + +// The Tail Sampling processor will use a set of policies to determine which received traces to keep +// and send to Tempo. +otelcol.processor.tail_sampling "errors" { + // Total wait time from the start of a trace before making a sampling decision. Note that smaller time + // periods can potentially cause a decision to be made before the end of a trace has occurred. + decision_wait = "30s" + + // The following policies follow a logical OR pattern, meaning that if any of the policies match, + // the trace will be kept. For logical AND, you can use the `and` policy. Every span of a trace is + // examined by each policy in turn. A match will cause a short-circuit. + + // This policy defines that traces that contain errors should be kept. + policy { + // The name of the policy can be used for logging purposes. + name = "sample-erroring-traces" + // The type must match the type of policy to be used, in this case examing the status code + // of every span in the trace. + type = "status_code" + // This block determines the error codes that should match in order to keep the trace, + // in this case the OpenTelemetry 'ERROR' code. + status_code { + status_codes = [ "ERROR" ] + } + } + + // This policy defines that only traces that are longer than 200ms in total should be kept. + policy { + // The name of the policy can be used for logging purposes. + name = "sample-long-traces" + // The type must match the policy to be used, in this case the total latency of the trace. + type = "latency" + // This block determines the total length of the trace in milliseconds. + latency { + threshold_ms = 200 + } + } + + // The output block forwards the kept traces onto the batch processor, which will marshall them + // for exporting to Tempo. + output { + traces = [otelcol.processor.batch.default.input] + } +} + +// The Spanmetrics Connector will generate RED metrics based on the incoming trace span data. +otelcol.connector.spanmetrics "tracemetrics" { + // The namespace explicit adds a prefix to all the generated span metrics names. + // In this case, we'll ensure they match as closely as possible those generated by Tempo. + namespace = "traces.spanmetrics" + + // Each extra dimension (metrics label) to be added to the generated metrics from matching span attributes. These + // need to be defined with a name and optionally a default value (in the following cases, we do not want a default + // value if the span attribute is not present). + dimension { + name = "http.method" + } + dimension { + name = "http.target" + } + dimension { + name = "http.status_code" + } + dimension { + name = "service.version" + } + + // A histogram block must be present, either explicitly defining bucket values or via an exponential block. + // We do the latter here. + histogram { + explicit { + } + } + + // The exemplar block is added to ensure we generate exemplars for traces on relevant metric values. + exemplars { + enabled = true + } + + // Generated metrics data is in OTLP format. We send this data to the OpenTelemetry Prometheus exporter to ensure + // it gets transformed into Prometheus format data. + output { + metrics = [otelcol.exporter.prometheus.tracemetrics.input] + } +} + +// The Servicegraph Connector will generate service graph metrics (edges and nodes) based on incoming trace spans. +otelcol.connector.servicegraph "tracemetrics" { + // Extra dimensions (metrics labels) to be added to the generated metrics from matching span attributes. + // For this component, this is defined as an array. There are no default values and the labels will not be generated + // for missing span attributes. + dimensions = [ + "http.method", + "http.target", + "http.status_code", + "service.version", + ] + + // Generated metrics data is in OTLP format. We send this data to the OpenTelemetry Prometheus exporter to ensure + // it gets transformed into Prometheus format data. + output { + metrics = [otelcol.exporter.prometheus.tracemetrics.input] + } +} + +otelcol.exporter.prometheus "tracemetrics" { + // Forward to our local Prometheus remote writer which will send the metrics to Mimir. + forward_to = [prometheus.remote_write.mimir.receiver] +} +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Profiling +///////////////////////////////////////////////////////////////////////////////////////////////////////////// + +pyroscope.write "pyroscope" { + endpoint { + url = json_path(local.file.endpoints.content, ".profiles.url")[0] + basic_auth { + username = json_path(local.file.endpoints.content, ".profiles.basicAuth.username")[0] + password = json_path(local.file.endpoints.content, ".profiles.basicAuth.password")[0] + } + } + external_labels = {} +} + +pyroscope.ebpf "rinoadocker" { + forward_to = [pyroscope.write.pyroscope.receiver] + targets = discovery.docker.rinoadocker.targets +} \ No newline at end of file diff --git a/ansible/app-configs/grafana_alloy_endpoints.json.j2 b/ansible/app-configs/grafana_alloy_endpoints.json.j2 new file mode 100644 index 00000000..d50b71a4 --- /dev/null +++ b/ansible/app-configs/grafana_alloy_endpoints.json.j2 @@ -0,0 +1,34 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +{ + "metrics": { + "url": "http://grafana-mimir:9009/api/v1/push", + "basicAuth": { + "username": "", + "password": "" + } + }, + "logs": { + "url": "http://grafana-loki:3100/loki/api/v1/push", + "basicAuth": { + "username": "", + "password": "" + } + }, + "traces": { + "url": "http://grafana-tempo:4317", + "basicAuthToken": "", + "tls": { + "insecure": true, + "insecureSkipVerify": true + } + }, + "profiles": { + "url": "http://grafana-pyroscope:4040", + "basicAuth": { + "username": "", + "password": "" + } + } +} \ No newline at end of file diff --git a/ansible/app-configs/grafana_tempo_tempo.yaml.j2 b/ansible/app-configs/grafana_tempo_tempo.yaml.j2 new file mode 100644 index 00000000..fbfd0050 --- /dev/null +++ b/ansible/app-configs/grafana_tempo_tempo.yaml.j2 @@ -0,0 +1,54 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + + +server: + http_listen_port: 3200 + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + grpc: + opencensus: + +ingester: + max_block_duration: 5m # cut the headblock when this much time passes. this is being set for demo purposes and should probably be left alone normally + +compactor: + compaction: + block_retention: 1h # overall Tempo trace retention. set for demo purposes + +# metrics_generator: +# registry: +# external_labels: +# source: tempo +# cluster: docker-compose +# storage: +# path: /tmp/tempo/generator/wal +# remote_write: +# - url: http://grafana-alloy:12345/api/v1/write +# send_exemplars: true + +storage: + trace: + backend: s3 # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the the wal locally + s3: + bucket: tempo # how to store data in s3 + endpoint: minio:9000 + access_key: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['MINIO_TEMPO_STORAGE_ACCESS_KEY'] }} + secret_key: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['MINIO_TEMPO_STORAGE_SECRET_KEY'] }} + insecure: true + +usage_report: + reporting_enabled: false \ No newline at end of file diff --git a/ansible/app-configs/homepage_settings.yaml.j2 b/ansible/app-configs/homepage_settings.yaml.j2 new file mode 100644 index 00000000..4c844417 --- /dev/null +++ b/ansible/app-configs/homepage_settings.yaml.j2 @@ -0,0 +1,60 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +--- +# For configuration options and examples, please see: +# https://gethomepage.dev/en/configs/settings + +providers: + openweathermap: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['HOMEPAGE_OPENWEATHERMAP_API_KEY'] }} + # weatherapi: weatherapiapikey +title: Rinoa Dashboard (trez.WTF) +headerStyle: underlined +color: slate +showStats: true +statusStyle: "dot" +favicon: /icons/favicon.ico +useEqualHeights: false +hideErrors: false +searchDescriptions: true +showSearchSuggestions: true +provider: duckduckgo + +layout: + System Administration: + style: row + columns: 4 + # fiveColumns: true + Infrastructure/App Performance Monitoring: + style: row + columns: 4 + Automation: + style: columns + row: 2 + Code/DevOps: + style: columms + row: 2 + Privacy/Security: + style: columns + row: 5 + Social: + style: columns + row: 4 + Lifestyle: + style: row + columns: 4 + Personal Services: + style: row + columns: 4 + Professional Services: + style: row + columns: 3 + Servarr Stack: + style: row + columns: 3 + Downloaders: + style: row + columns: 3 + Media Library: + style: row + columns: 4 diff --git a/ansible/app-configs/invoice-ninja_invoice-ninja.env.j2 b/ansible/app-configs/invoice-ninja_invoice-ninja.env.j2 new file mode 100644 index 00000000..284dcb14 --- /dev/null +++ b/ansible/app-configs/invoice-ninja_invoice-ninja.env.j2 @@ -0,0 +1,52 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +# IN application vars +IN_APP_URL=http://in.localhost:8003 +IN_APP_KEY= +IN_APP_DEBUG=true +IN_REQUIRE_HTTPS=false +IN_PHANTOMJS_PDF_GENERATION=false +IN_PDF_GENERATOR=snappdf +IN_TRUSTED_PROXIES='*' + + +IN_QUEUE_CONNECTION=database + +# DB connection +IN_DB_HOST=db +IN_DB_PORT=3306 +IN_DB_DATABASE=ninja +IN_DB_USERNAME=ninja +IN_DB_PASSWORD=ninja + +# Create initial user +# Default to these values if empty +# IN_USER_EMAIL=admin@example.com +# IN_PASSWORD=changeme! +IN_USER_EMAIL= +IN_PASSWORD= + +# Mail options +IN_MAIL_MAILER=log +IN_MAIL_HOST=smtp.mailtrap.io +IN_MAIL_PORT=2525 +IN_MAIL_USERNAME=null +IN_MAIL_PASSWORD=null +IN_MAIL_ENCRYPTION=null +IN_MAIL_FROM_ADDRESS='user@example.com' +IN_MAIL_FROM_NAME='Self Hosted User' + +# MySQL +IN_MYSQL_ROOT_PASSWORD=ninjaAdm1nPassword +IN_MYSQL_USER=ninja +IN_MYSQL_PASSWORD=ninja +IN_MYSQL_DATABASE=ninja + +# GoCardless/Nordigen API key for banking integration +NORDIGEN_SECRET_ID= +NORDIGEN_SECRET_KEY= + +# V4 env vars +# DB_STRICT=false +# APP_CIPHER=AES-256-CBC diff --git a/ansible/app-configs/komodo_core.config.toml.j2 b/ansible/app-configs/komodo_core.config.toml.j2 new file mode 100644 index 00000000..9b98615a --- /dev/null +++ b/ansible/app-configs/komodo_core.config.toml.j2 @@ -0,0 +1,477 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +########################### +# 🦎 KOMODO CORE CONFIG 🦎 # +########################### + +## This is the offical "Default" config file for Komodo Core. +## It serves as documentation for the meaning of the fields. +## It is located at `https://github.com/mbecker20/komodo/blob/main/config/core.config.toml`. + +## All fields with a "Default" provided are optional. If they are +## left out of the file, the "Default" value will be used. + +## This file is bundled into the official image, `ghcr.io/mbecker20/komodo`, +## as the default config at `/config/config.toml`. +## Komodo can start with no external config file mounted. + +## There is usually no need to create this file on your host. +## Most fields can instead be configured using environment variables. +## Environment variables will override values set in this file. + +## This will be the document title on the web page. +## Env: KOMODO_TITLE +## Default: 'Komodo' +title = "Komodo @ Rinoa" + +## This should be the url used to access Komodo in browser, potentially behind DNS. +## Eg https://komodo.example.com or http://12.34.56.78:9120. This should match the address configured in your Oauth app. +## Env: KOMODO_HOST +## Required, no default. +host = "https://komodo.trez.wtf" + +## The port the core system will run on. +## Env: KOMODO_PORT +## Default: 9120 +port = 9120 + +## This is the token used to authenticate core requests to periphery. +## Ensure this matches a passkey in the connected periphery configs. +## If the periphery servers don't have passkeys configured, this doesn't need to be changed. +## Env: KOMODO_PASSKEY or KOMODO_PASSKEY_FILE +## Required, no default +passkey = "JgzFdZYbE7JfH5zhrh5pWUEQEWA4MCXG" + +## Ensure a server with this address exists on Core +## upon first startup. Example: `https://periphery:8120` +## Env: KOMODO_FIRST_SERVER +## Optional, no default. +first_server = "" + +## Disables write support on resources in the UI. +## This protects users that that would normally have write priviledges during their UI usage, +## when they intend to fully rely on ResourceSyncs to manage config. +## Env: KOMODO_UI_WRITE_DISABLED +## Default: false +ui_write_disabled = false + +## Disables the confirm dialogs on all actions. All buttons will now be double-click. +## Useful when only having http connection to core, as UI quick-copy button won't work. +## Env: KOMODO_DISABLE_CONFIRM_DIALOG +## Default: false +disable_confirm_dialog = false + +## Configure the directory for sync files (inside the container). +## There shouldn't be a need to change this, just mount a volume. +## Env: KOMODO_SYNC_DIRECTORY +## Default: /syncs +sync_directory = "/syncs" + +## Configure the repo directory (inside the container). +## There shouldn't be a need to change this, just mount a volume. +## Env: KOMODO_REPO_DIRECTORY +## Default: /repo-cache +repo_directory = "/repo-cache" + +## Configure the action directory (inside the container). +## There shouldn't be a need to change this, or even mount a volume. +## Env: KOMODO_ACTION_DIRECTORY +## Default: /action-cache +action_directory = "/action-cache" + +################ +# AUTH / LOGIN # +################ + +## Allow user login with a username / password. +## The password will be hashed and stored in the db for login comparison. +## +## NOTE: +## Komodo has no API to recover account logins, but if this happens you can doctor the database using Mongo Compass. +## Create a new Komodo user (Sign Up button), login to the database with Compass, note down your old users username and _id. +## Then delete the old user, and update the new user to have the same username and _id. +## Make sure to set `enabled: true` and maybe `admin: true` on the new user as well, while using Compass. +## +## Env: KOMODO_LOCAL_AUTH +## Default: false +local_auth = true + +## Normally new users will be registered, but not enabled until an Admin enables them. +## With `disable_user_registration = true`, only the first user to log in will registered as a user. +## Env: KOMODO_DISABLE_USER_REGISTRATION +## Default: false +disable_user_registration = false + +## New users will be automatically enabled when they sign up. +## Otherwise, new users will be disabled on first login. +## The first user to login will always be enabled on creation. +## Env: KOMODO_ENABLE_NEW_USERS +## Default: false +enable_new_users = false + +## Allows all users to have Read level access to all resources. +## Env: KOMODO_TRANSPARENT_MODE +## Default: false +transparent_mode = false + +## Normally all enabled users can create resources. +## If `disable_non_admin_create = true`, only admin users can create resources. +## Env: KOMODO_DISABLE_NON_ADMIN_CREATE +## Default: false +disable_non_admin_create = false + +## Optionally provide a specific jwt secret. +## Passing nothing or an empty string will cause one to be generated on every startup. +## This means users will have to log in again if Komodo restarts. +## Env: KOMODO_JWT_SECRET or KOMODO_JWT_SECRET_FILE +## Default: empty string, meaning a random secret will be generated at startup. +jwt_secret = "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['KOMODO_JWT_SECRET'] }}" + +## Specify how long a user can stay logged in before they have to log in again. +## All jwts are invalidated on application restart unless `jwt_secret` is set. +## Env: KOMODO_JWT_TTL +## Options: 1-hr, 12-hr, 1-day, 3-day, 1-wk, 2-wk, 30-day +## Default: 1-day. +jwt_ttl = "1-day" + +############# +# OIDC Auth # +############# + +## Enable logins with configured OIDC provider. +## Env: KOMODO_OIDC_ENABLED +## Default: false +oidc_enabled = false + +## Give the provider address. +## +## The path, ie /application/o/komodo for Authentik, +## is provider and configuration specific. +## +## Note. this address must be reachable from Komodo Core container. +## +## Env: KOMODO_OIDC_PROVIDER +## Optional, no default. +oidc_provider = "https://oidc.provider.internal/application/o/komodo" + +## Configure OIDC user redirect host. +## +## This is the host address users are redirected to in their browser, +## and may be different from `oidc_provider` host depending on your networking. +## If not provided (or empty string ""), the `oidc_provider` will be used. +## +## Note. DO NOT include the `path` part of the URL. +## Example: `https://oidc.provider.external` +## +## Env: KOMODO_OIDC_REDIRECT_HOST +## Optional, no default. +oidc_redirect_host = "" + +## Give the OIDC Client ID. +## Env: KOMODO_OIDC_CLIENT_ID or KOMODO_OIDC_CLIENT_ID_FILE +oidc_client_id = "" + +## Give the OIDC Client Secret. +## Env: KOMODO_OIDC_CLIENT_SECRET or KOMODO_OIDC_CLIENT_SECRET_FILE +oidc_client_secret = "" + +## If true, use the full email for usernames. +## Otherwise, the @address will be stripped, +## making usernames more concise. +## Env: KOMODO_OIDC_USE_FULL_EMAIL +## Default: false. +oidc_use_full_email = false + +## Some providers attach other audiences in addition to the client_id. +## If you have this issue, `Invalid audiences: `...` is not a trusted audience"`, +## you can add the audience `...` to the list here (assuming it should be trusted). +## Env: KOMODO_OIDC_ADDITIONAL_AUDIENCES or KOMODO_OIDC_ADDITIONAL_AUDIENCES_FILE +## Default: empty +oidc_additional_audiences = [] + +######### +# OAUTH # +######### + +## Google + +## Env: KOMODO_GOOGLE_OAUTH_ENABLED +## Default: false +google_oauth.enabled = false + +## Env: KOMODO_GOOGLE_OAUTH_ID or KOMODO_GOOGLE_OAUTH_ID_FILE +## Required if google_oauth is enabled. +google_oauth.id = "" + +## Env: KOMODO_GOOGLE_OAUTH_SECRET or KOMODO_GOOGLE_OAUTH_SECRET_FILE +## Required if google_oauth is enabled. +google_oauth.secret = "" + +## Github + +## Env: KOMODO_GITHUB_OAUTH_ENABLED +## Default: false +github_oauth.enabled = false + +## Env: KOMODO_GITHUB_OAUTH_ID or KOMODO_GITHUB_OAUTH_ID_FILE +## Required if github_oauth is enabled. +github_oauth.id = "" + +## Env: KOMODO_GITHUB_OAUTH_SECRET or KOMODO_GITHUB_OAUTH_SECRET_FILE +## Required if github_oauth is enabled. +github_oauth.secret = "" + +############ +# Security # +############ + +## Enable HTTPS server using the given key and cert. +## Env: KOMODO_SSL_ENABLED +## Default: false +ssl_enabled = false + +## Path to the ssl key. +## Env: KOMODO_SSL_KEY_FILE +## Default: /config/ssl/key.pem +ssl_key_file = "/config/ssl/key.pem" + +## Path to the ssl cert. +## Env: KOMODO_SSL_CERT_FILE +## Default: /config/ssl/cert.pem +ssl_cert_file = "/config/ssl/cert.pem" + +############ +# DATABASE # +############ + +## Configure the database connection in one of the following ways: + +## Pass a full Mongo URI to the database. +## Example: mongodb://username:password@localhost:27017 +## Env: KOMODO_DATABASE_URI or KOMODO_DATABASE_URI_FILE +## Optional, can usually use `address`, `username`, `password` instead. +database.uri = "mongodb://komodo:jtyl2U8KZPUe8V9MOTXQDYRlg7QemGuF@komodo-ferretdb:27017/komodo?authMechanism=PLAIN" + +## ==== * OR * ==== ## + +# Construct the address as mongodb://{username}:{password}@{address} +## Env: KOMODO_DATABASE_ADDRESS +# database.address = "localhost:27017" +## Env: KOMODO_DATABASE_USERNAME or KOMODO_DATABASE_USERNAME_FILE +# database.username = "" +## Env: KOMODO_DATABASE_PASSWORD or KOMODO_DATABASE_PASSWORD_FILE +# database.password = "" + +## ==== other ==== + +## Komodo will create its collections under this database name. +## The only reason to change this is if multiple Komodo Cores share the same db. +## Env: KOMODO_DATABASE_DB_NAME +## Default: komodo. +database.db_name = "komodo" + +## This is the assigned app_name of the mongo client. +## The only reason to change this is if multiple Komodo Cores share the same db. +## Env: KOMODO_DATABASE_APP_NAME +## Default: komodo_core. +database.app_name = "komodo_core" + +############ +# WEBHOOKS # +############ + +## This token must be given to git provider during repo webhook config. +## The secret configured on the git provider side must match the secret configured here. +## If not provided, +## Env: KOMODO_WEBHOOK_SECRET or KOMODO_WEBHOOK_SECRET_FILE +## Optional, no default. +webhook_secret = "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['KOMODO_WEBHOOK_SECRET'] }}" + +## An alternate base url that is used to recieve git webhook requests. +## If empty or not specified, will use 'host' address as base. +## This is useful if Komodo is on an internal network, but can have a +## proxy just allowing through the webhook listener api using NGINX. +## Env: KOMODO_WEBHOOK_BASE_URL +## Default: empty (none) +webhook_base_url = "" + +## Configure Github webhook app. Enables webhook management apis. +## +## Env: KOMODO_GITHUB_WEBHOOK_APP_APP_ID or KOMODO_GITHUB_WEBHOOK_APP_APP_ID_FILE +# github_webhook_app.app_id = 1234455 # Find on the app page. +## Env: +## - KOMODO_GITHUB_WEBHOOK_APP_INSTALLATIONS_IDS or KOMODO_GITHUB_WEBHOOK_APP_INSTALLATIONS_IDS_FILE +## - KOMODO_GITHUB_WEBHOOK_APP_INSTALLATIONS_NAMESPACES +# github_webhook_app.installations = [ +# ## Find the id after installing the app to user / organization. "namespace" is the username / organization name. +# { id = 1234, namespace = "mbecker20" } +# ] + +## The path to Github webhook app private key. +## This is defaulted to `/github/private-key.pem`, and doesn't need to be changed if running core in Docker. +## Just mount the private key pem file on the host to `/github/private-key.pem` in the container. +## Eg. `/your/path/to/key.pem : /github/private-key.pem` +## Env: KOMODO_GITHUB_WEBHOOK_APP_PK_PATH +# github_webhook_app.pk_path = "/path/to/pk.pem" + +########### +# LOGGING # +########### + +## Specify the logging verbosity +## Env: KOMODO_LOGGING_LEVEL +## Options: off, error, warn, info, debug, trace +## Default: info +logging.level = "info" + +## Specify the logging format for stdout / stderr. +## Env: KOMODO_LOGGING_STDIO +## Options: standard, json, none +## Default: standard +logging.stdio = "standard" + +## Optionally specify a opentelemetry otlp endpoint to send traces to. +## Example: http://localhost:4317 +## Env: KOMODO_LOGGING_OTLP_ENDPOINT +logging.otlp_endpoint = "" + +## Set the opentelemetry service name. +## This will be attached to the telemetry Komodo will send. +## Env: KOMODO_LOGGING_OPENTELEMETRY_SERVICE_NAME +## Default: "Komodo" +logging.opentelemetry_service_name = "Komodo" + +########### +# PRUNING # +########### + +## The number of days to keep historical system stats around, or 0 to disable pruning. +## Stats older that are than this number of days are deleted on a daily cycle. +## Env: KOMODO_KEEP_STATS_FOR_DAYS +## Default: 14 +keep_stats_for_days = 14 + +## The number of days to keep alerts around, or 0 to disable pruning. +## Alerts older that are than this number of days are deleted on a daily cycle. +## Env: KOMODO_KEEP_ALERTS_FOR_DAYS +## Default: 14 +keep_alerts_for_days = 14 + +################## +# POLL INTERVALS # +################## + +## Controls the rate at which servers are polled for health, system stats, and container status. +## This affects network usage, and the size of the stats stored in mongo. +## Env: KOMODO_MONITORING_INTERVAL +## Options: 1-sec, 5-sec, 15-sec, 30-sec, 1-min, 2-min, 5-min, 15-min +## Default: 15-sec +monitoring_interval = "15-sec" + +## Interval at which to poll Resources for any updates / automated actions. +## Env: KOMODO_RESOURCE_POLL_INTERVAL +## Options: `15-sec`, `1-min`, `5-min`, `15-min`, `1-hr`. +## Default: 5-min +resource_poll_interval = "5-min" + +################### +# CLOUD PROVIDERS # +################### + +## Komodo can build images by deploying AWS EC2 instances, +## running the build, and afterwards destroying the instance. + +## Additionally, Komodo can deploy cloud VPS on AWS EC2 and Hetzner. +## Use the Template resource to configure launch preferences. +## Hetzner is not supported for builds as their pricing model is by the hour, +## while AWS is by the minute. This is very important for builds. + +## Provide AWS api keys for ephemeral builders / server launch +## Env: KOMODO_AWS_ACCESS_KEY_ID or KOMODO_AWS_ACCESS_KEY_ID_FILE +aws.access_key_id = "" +## Env: KOMODO_AWS_SECRET_ACCESS_KEY or KOMODO_AWS_SECRET_ACCESS_KEY_FILE +aws.secret_access_key = "" + +## Provide Hetzner api token for server launch +## Env: KOMODO_HETZNER_TOKEN or KOMODO_HETZNER_TOKEN_FILE +hetzner.token = "" + +################# +# GIT PROVIDERS # +################# + +## These will be available to attach to Builds, Repos, Stacks, and Syncs. +## They allow these Resources to clone private repositories. +## They cannot be configured on the environment. + +## configure git providers +# [[git_provider]] +# domain = "github.com" +# accounts = [ +# { username = "mbecker20", token = "access_token_for_account" }, +# { username = "moghtech", token = "access_token_for_other_account" }, +# ] + +# [[git_provider]] +# domain = "git.mogh.tech" # use a custom provider, like self-hosted gitea +# accounts = [ +# { username = "mbecker20", token = "access_token_for_account" }, +# ] + +# [[git_provider]] +# domain = "localhost:8000" # use a custom provider, like self-hosted gitea +# https = false # use http://localhost:8000 as base-url for clone +# accounts = [ +# { username = "mbecker20", token = "access_token_for_account" }, +# ] + +###################### +# REGISTRY PROVIDERS # +###################### + +## These will be available to attach to Builds and Stacks. +## They allow these Resources to pull private images. +## They cannot be configured on the environment. + +## configure docker registries +# [[docker_registry]] +# domain = "docker.io" +# accounts = [ +# { username = "mbecker2020", token = "access_token_for_account" } +# ] +# organizations = ["DockerhubOrganization"] + +[[gitea_rinoa]] +domain = "git.trez.wtf" +accounts = [ + { username = "gitea-sonarqube-bot", token = "594a3a9611bdb508bd6a3575e2ddb3ac4922a4da" } +] + +[[gitea_rinoa_local]] +domain = "http://gitea:3000" +accounts = [ + { username = "gitea-sonarqube-bot", token = "594a3a9611bdb508bd6a3575e2ddb3ac4922a4da" } +] + +# [[docker_registry]] +# domain = "git.mogh.tech" # use a custom provider, like self-hosted gitea +# accounts = [ +# { username = "mbecker20", token = "access_token_for_account" }, +# ] +# organizations = ["Mogh"] # These become available in the UI + +########### +# SECRETS # +########### + +## Provide Core based secrets. +## These will be available to interpolate into your Deployment / Stack environments, +## and will be hidden in the UI and logs. +## These are available to use on any Periphery (Server), +## but you can also limit access more by placing them in a single Periphery's config file instead. +## These cannot be configured in the Komodo Core environment, they must be passed in the file. + +# [secrets] +# SECRET_1 = "value_1" +# SECRET_2 = "value_2" diff --git a/ansible/app-configs/lidarr_config.xml.j2 b/ansible/app-configs/lidarr_config.xml.j2 new file mode 100644 index 00000000..7ff4318b --- /dev/null +++ b/ansible/app-configs/lidarr_config.xml.j2 @@ -0,0 +1,21 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + + + * + 8686 + 6868 + False + True + {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['LIDARR_API_KEY'] }} + Forms + master + trace + + + + Lidarr + Docker + auto + Enabled + \ No newline at end of file diff --git a/ansible/app-configs/lidify_settings_config.json.j2 b/ansible/app-configs/lidify_settings_config.json.j2 new file mode 100644 index 00000000..cc87a3b6 --- /dev/null +++ b/ansible/app-configs/lidify_settings_config.json.j2 @@ -0,0 +1,25 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +{ + "lidarr_address": "http://lidarr:8686", + "lidarr_api_key": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['LIDARR_API_KEY'] }}", + "spotify_client_secret": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['YOUR_SPOTIFY_SECRET'] }}", + "root_folder_path": "/data/media/music", + "spotify_client_id": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['YOUR_SPOTIFY_ID'] }}", + "spotify_client_secret": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['YOUR_SPOTIFY_SECRET'] }}", + "fallback_to_top_result": false, + "lidarr_api_timeout": 120.0, + "quality_profile_id": 1, + "metadata_profile_id": 1, + "search_for_missing_albums": false, + "dry_run_adding_to_lidarr": true, + "app_name": "lidify", + "app_rev": "0.09", + "app_url": "lidify.trez.wtf", + "last_fm_api_key": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['LASTFM_API_KEY'] }}", + "last_fm_api_secret": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['LASTFM_API_SECRET'] }}", + "mode": "LastFM", + "auto_start": false, + "auto_start_delay": 60 +} \ No newline at end of file diff --git a/ansible/app-configs/multi-scrobbler_config.json.j2 b/ansible/app-configs/multi-scrobbler_config.json.j2 new file mode 100644 index 00000000..b55e634a --- /dev/null +++ b/ansible/app-configs/multi-scrobbler_config.json.j2 @@ -0,0 +1,63 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +{ + "sourceDefaults": { + "maxPollRetries": 0, // optional, default # of automatic polling restarts on error. can be overridden by property in individual config + "maxRequestRetries": 1, // optional, default # of http request retries a source can make before error is thrown. can be overridden by property in individual config + "retryMultiplier": 1.5 // optional, default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying). can be overridden by property in individual config + }, + "clientDefaults": { + "maxRequestRetries": 1, // optional, default # of http request retries a client can make before error is thrown. can be overridden by property in individual config + "retryMultiplier": 1.5 // optional, default retry delay multiplier (retry attempt * multiplier = # of seconds to wait before retrying). can be overridden by property in individual config + }, + "clients": [ + { + "name": "Last.fm Client", + "enable": true, + "configureAs": "client", + "data": { + "apiKey": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['LASTFM_API_KEY'] }}", + "secret": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['LASTFM_API_SECRET'] }}", + "redirectUri": "http://localhost:9078/lastfm/callback" + } + }, + { + "name": "Last.fm Source", + "enable": true, + "configureAs": "source", + "data": { + "apiKey": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['LASTFM_API_KEY'] }}", + "secret": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['LASTFM_API_SECRET'] }}", + "redirectUri": "http://localhost:9078/lastfm/callback" + } + }, + { + "name": "Maloja", + "enable": true, + "data": { + "url": "http://maloja:42010", + "apiKey": "myMalojaKey" + } + }, + { + "name": "ListenBrainz Client", + "enable": true, + "configureAs": "client", + "data": { + "token": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['MALOJA_LISTENBRAINZ_TOKEN'] }}", + "username": "Trez.One" + } + }, + { + "name": "ListenBrainz Source", + "enable": true, + "configureAs": "source", + "data": { + "token": "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['MALOJA_LISTENBRAINZ_TOKEN'] }}", + "username": "Trez.One" + } + } + ] + } +} \ No newline at end of file diff --git a/ansible/app-configs/postal_postal.yml.j2 b/ansible/app-configs/postal_postal.yml.j2 new file mode 100644 index 00000000..f1540922 --- /dev/null +++ b/ansible/app-configs/postal_postal.yml.j2 @@ -0,0 +1,59 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + +version: 2 + +postal: + web_hostname: post.trez.wtf + web_protocol: http + smtp_hostname: post.trez.wtf + use_ip_pools: false + signing_key_path: /config/signing.key + trusted_proxies: [ "172.18.0.0/16" ] + +web_server: + default_port: 5000 + default_bind_address: 0.0.0.0 + +main_db: + host: mariadb + username: postal + password: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['POSTAL_MYSQL_PASSWORD'] }} + database: postal + +message_db: + host: mariadb + username: postal + password: {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['POSTAL_MYSQL_PASSWORD'] }} + prefix: postal + +smtp_server: + default_port: 25 + default_bind_address: "::" + +dns: + # Specify the DNS records that you have configured. Refer to the documentation at + # https://github.com/atech/postal/wiki/Domains-&-DNS-Configuration for further + # information about these. + mx_records: + - mx.post.trez.wtf + spf_include: spf.post.trez.wtf + return_path_domain: rp.post.trez.wtf + route_domain: routes.post.trez.wtf + track_domain: track.post.trez.wtf + +smtp: + # Specify an SMTP server that can be used to send messages from the Postal management + # system to users. You can configure this to use a Postal mail server once the + # your installation has been set up. + host: postal-smtp + port: 25 + username: rinoa/postal-smtp + password: "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['POSTAL_SMTP_AUTH_PASSWORD'] }}" + from_name: Postal @ Rinoa + from_address: noreply@trez.wtf + +rails: + # This is generated automatically by the config initialization. It should be a random + # string unique to your installation. + secret_key: "{{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['POSTAL_RAILS_SECRET_KEY'] }}" diff --git a/ansible/app-configs/prowlarr_config.xml.j2 b/ansible/app-configs/prowlarr_config.xml.j2 new file mode 100644 index 00000000..f45b8eea --- /dev/null +++ b/ansible/app-configs/prowlarr_config.xml.j2 @@ -0,0 +1,21 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + + + * + 9696 + 6969 + False + True + {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['PROWLARR_API_KEY'] }} + Forms + Enabled + master + info + + + + Prowlarr + Docker + light + \ No newline at end of file diff --git a/ansible/app-configs/radarr_config.xml.j2 b/ansible/app-configs/radarr_config.xml.j2 new file mode 100644 index 00000000..e9a9baaa --- /dev/null +++ b/ansible/app-configs/radarr_config.xml.j2 @@ -0,0 +1,21 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + + + info + * + False + + 7878 + + {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['RADARR_API_KEY'] }} + Forms + Docker + 9898 + True + master + + Radarr + auto + Enabled + \ No newline at end of file diff --git a/ansible/app-configs/readarr_config.xml.j2 b/ansible/app-configs/readarr_config.xml.j2 new file mode 100644 index 00000000..5eec003e --- /dev/null +++ b/ansible/app-configs/readarr_config.xml.j2 @@ -0,0 +1,21 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = 'rinoa-docker/env' %} + + + * + 8787 + 6868 + False + True + {{ lookup('community.hashi_vault.vault_kv2_get', 'env', engine_mount_point='rinoa-docker', url=vault_addr, token=vault_token_cleaned)['secret']['READARR_API_KEY'] }} + Forms + develop + info + + + + Readarr + Docker + auto + Enabled + \ No newline at end of file diff --git a/ansible/app-configs/sonarr_config.xml.j2 b/ansible/app-configs/sonarr_config.xml.j2 new file mode 100644 index 00000000..1afdc004 --- /dev/null +++ b/ansible/app-configs/sonarr_config.xml.j2 @@ -0,0 +1,22 @@ +{% set vault_addr = 'https://vault.trez.wtf' %} +{% set secrets_path = rinoa-docker/env %} + + + info + False + 8989 + 9898 + + * + 386baee1c0e741bea4a91f1f39c57f68 + Forms + Docker + True + main + Sonarr + 514 + Enabled + + + auto + \ No newline at end of file diff --git a/ansible/collections/requirements.yml b/ansible/collections/requirements.yml new file mode 100644 index 00000000..6e5e6884 --- /dev/null +++ b/ansible/collections/requirements.yml @@ -0,0 +1,7 @@ +--- +collections: + - name: community.hashi_vault + version: 6.2.0 + + - name: community.general + version: 8.2.0 \ No newline at end of file diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml new file mode 100644 index 00000000..c8cea766 --- /dev/null +++ b/ansible/group_vars/all.yml @@ -0,0 +1,14 @@ +vault_addr: "https://vault.trez.wtf" +vault_token: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 66373236656261373330343233616231386539616566613864306436613635323533336365383232 + 6636653139393566643265303135343864363632393035380a643566373137316363626438356431 + 64653237313866316537326565386164373564353166346334663638636531353337303937346466 + 3539366634393337620a653133336530333963343638643934303336653935363932643665353234 + 63343565663632633563396131346139666236313863663332386131633831633566373366613738 + 63343634313539336534666632313736343338623538303434316230383764643432646663356238 + 61373132633062346436363036333533623931313037306633616662623032616137613734343638 + 63633031616161623437623935346366636433653435646333313638376161663237323130636433 + 31383031646666626163323966393738386233346137326231366263316532343563 +vault_token_cleaned: "{{ vault_token | regex_replace('\\n', '') }}" +secrets_path: "rinoa-docker/env" diff --git a/ansible/host_vars.yml b/ansible/host_vars.yml new file mode 100644 index 00000000..3c50f7d9 --- /dev/null +++ b/ansible/host_vars.yml @@ -0,0 +1,12 @@ +ansible_host: 192.168.1.254 +ansible_python_interpreter: /usr/bin/python3 +ansible_ssh_port: 22 +ansible_ssh_user: charish +ansible_ssh_pass: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 38346631616139316365316566386362396661323163306339303635646331373061323531626431 + 3435373031363739356261656239633835393963636663370a613166653463656337666366633639 + 37373637326633363430633336646165343764303063663636313835326130663532323037663331 + 6332353339656134370a353435396532663932313535646636333262353238386331313764633635 + 63383065623930653134666261353439366535646661383434386261393232373432353937636535 + 3432336137393737643735346665303832653630316439333565 diff --git a/ansible/ssh_pass.yml b/ansible/ssh_pass.yml new file mode 100644 index 00000000..9b502d17 --- /dev/null +++ b/ansible/ssh_pass.yml @@ -0,0 +1,7 @@ +$ANSIBLE_VAULT;1.1;AES256 +65353131326537376561616630666531353731653835306564323565383332653437633533313932 +6239663065306339366536326432323534303364663862350a353034623936363066303164333434 +32666331326332363463383234316136323031626330366132643034376439616339396662636236 +3633393039376438630a326138653031656465373966356564336463643465613638313838393166 +36626366356266636535613862333631386231626134376264363731353264613261633037646662 +6431393837653564366531316332616232336365636533643036