From 9ce18e4accafaa40dab702201fff7d101d66a194 Mon Sep 17 00:00:00 2001 From: Andrew Stoltz <1578013+astoltz@users.noreply.github.com> Date: Wed, 17 Jun 2026 02:39:55 -0500 Subject: [PATCH] fix(irc): inject GX10 cloak keys from Secret --- apps-gx10/irc/irc.yaml | 1354 ++++++++++++++++++++++++++++++++++++++++ apps/irc/irc.yaml | 24 +- 2 files changed, 1372 insertions(+), 6 deletions(-) create mode 100644 apps-gx10/irc/irc.yaml diff --git a/apps-gx10/irc/irc.yaml b/apps-gx10/irc/irc.yaml new file mode 100644 index 0000000..c517ff7 --- /dev/null +++ b/apps-gx10/irc/irc.yaml @@ -0,0 +1,1354 @@ +# ============================================================================ +# IRC stack rehomed from OLD RKE2 cluster (infra-irc, ns irc) to GX10 K8s. +# UnrealIRCd + Anope IRC Services + The Lounge web client. +# +# GX10 adaptations vs OLD bluejay-infra/apps/irc/irc.yaml: +# - OnePasswordItem REPLACED by directly-copied Secrets (no OnePassword operator on GX10). +# irc-credentials is applied separately; cloak keys are injected from unrealircd-cloak-keys. +# - unrealircd image -> localhost/fc-unrealircd:6.1.9.1-arm64 (built on GX10 from +# DjLegolas/unrealircd-docker, alpine:3.19 base, UnrealIRCd 6.1.9.1 from source; +# djlegolas/unrealircd:6.1.9.1 on Docker Hub is amd64-ONLY -> would crashloop on arm64). +# imagePullPolicy: Never (image is ctr-imported, not in a registry). +# - anope image PINNED anope/anope:2.0.15 (multi-arch incl arm64; was :latest = arm64 too +# but pinned for reproducibility). +# - thelounge ghcr.io/thelounge/thelounge:4.4.3 (multi-arch incl arm64) — unchanged. +# - PVCs -> storageClassName: local-path (GX10 default; OLD was longhorn). +# - IRC TCP 6667/6697 exposed via a dedicated MetalLB LoadBalancer on the PROD pool +# (10.0.57.204) instead of OLD's Traefik irc/irctls entryPoints (GX10 Traefik has no +# such entryPoints). 8067 (anope uplink) stays internal on a separate ClusterIP svc. +# - Stripped ArgoCD instance labels / status / server metadata. +# ============================================================================ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: irc + labels: + app.kubernetes.io/part-of: gx10-migration +--- +# TLS Certificate for IRC (server SNI irc.iamworkin.lan) +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: irc-tls + namespace: irc +spec: + secretName: irc-tls + issuerRef: + name: step-ca-acme + kind: ClusterIssuer + dnsNames: + - irc.iamworkin.lan +--- +# TLS Certificate for The Lounge web IRC +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: webirc-tls + namespace: irc +spec: + secretName: webirc-tls + issuerRef: + name: step-ca-acme + kind: ClusterIssuer + dnsNames: + - webirc.iamworkin.lan +--- +# The Lounge configuration +apiVersion: v1 +kind: ConfigMap +metadata: + name: thelounge-config + namespace: irc +data: + config.js: | + "use strict"; + + module.exports = { + public: true, + host: "0.0.0.0", + port: 9000, + reverseProxy: true, + maxHistory: 2500, + theme: "thelounge-theme-flowercore", + prefetch: false, + disableMediaPreview: true, + fileUpload: { + enable: false + }, + defaults: { + name: "BlueJayIRC", + host: "unrealircd.irc.svc", + port: 6667, + password: "", + tls: false, + rejectUnauthorized: true, + nick: "BlueJayWeb%%", + username: "bluejayweb", + realname: "BlueJay Web IRC", + join: "#general" + }, + lockNetwork: true, + leaveMessage: "BlueJay Web IRC" + }; +--- +# FlowerCore / Blue Jay theme package for The Lounge +apiVersion: v1 +kind: ConfigMap +metadata: + name: thelounge-flowercore-theme + namespace: irc +data: + package.json: | + { + "name": "thelounge-theme-flowercore", + "version": "1.0.0", + "description": "FlowerCore Blue Jay theme for The Lounge", + "main": "package.json", + "keywords": [ + "thelounge", + "thelounge-theme" + ], + "thelounge": { + "type": "theme", + "name": "FlowerCore Blue Jay", + "css": "theme.css", + "files": [ + "bluejay-logo.svg", + "bluejay-bg.svg" + ] + } + } + theme.css: | + :root { + --fc-bg: #0a1628; + --fc-surface: #111d33; + --fc-surface-2: #162844; + --fc-border: #1e3a5f; + --fc-accent: #2b8aff; + --fc-accent-soft: rgba(43, 138, 255, 0.22); + --fc-gold: #ffb300; + --fc-text: #e8edf5; + --fc-text-muted: #9db1c8; + --fc-success: #3db86a; + --fc-danger: #e84545; + --body-color: var(--fc-text); + --body-color-muted: var(--fc-text-muted); + --body-bg-color: var(--fc-bg); + --button-color: var(--fc-accent); + --button-text-color-hover: #ffffff; + --overlay-bg-color: rgba(5, 12, 22, 0.84); + --link-color: #8bc3ff; + --window-bg-color: var(--fc-surface); + --window-heading-color: #f5f8ff; + --date-marker-color: rgba(43, 138, 255, 0.45); + --unread-marker-color: rgba(255, 179, 0, 0.6); + --highlight-bg-color: rgba(43, 138, 255, 0.12); + --highlight-border-color: var(--fc-gold); + --upload-progressbar-color: var(--fc-gold); + } + + body { + background: + radial-gradient(circle at top right, rgba(43, 138, 255, 0.22), transparent 30%), + linear-gradient(145deg, rgba(10, 22, 40, 0.98), rgba(12, 25, 46, 0.98)), + url("/packages/thelounge-theme-flowercore/bluejay-bg.svg"); + color: var(--fc-text); + font-family: "Trebuchet MS", "Segoe UI", Verdana, sans-serif; + } + + a, + a:focus, + a:hover { + color: var(--link-color); + } + + .window, + #confirm-dialog, + #context-menu, + .mentions-popup, + .textcomplete-menu { + background: rgba(17, 29, 51, 0.97); + border: 1px solid var(--fc-border); + box-shadow: 0 24px 60px rgba(3, 10, 18, 0.55); + } + + #loading .window, + #confirm-dialog { + background: + linear-gradient(180deg, rgba(14, 30, 54, 0.98), rgba(17, 29, 51, 0.98)), + url("/packages/thelounge-theme-flowercore/bluejay-bg.svg"); + border-color: rgba(43, 138, 255, 0.4); + } + + #loading .logo, + #loading .logo-inverted, + #sidebar .logo, + #sidebar .logo-inverted { + display: none !important; + } + + #loading-status-container, + #sidebar .logo-container { + position: relative; + } + + #loading-status-container::before { + content: ""; + display: block; + width: 96px; + height: 96px; + margin: 0 auto 16px; + background: url("/packages/thelounge-theme-flowercore/bluejay-logo.svg") center / contain no-repeat; + filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.45)); + } + + #loading-page-message::before { + content: "FlowerCore IRC"; + display: block; + margin-bottom: 10px; + color: #ffffff; + font-size: 30px; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; + } + + #loading-page-message::after { + content: "Blue Jay web chat for iamworkin.lan"; + display: block; + margin-top: 10px; + color: var(--fc-text-muted); + font-size: 14px; + letter-spacing: 0.08em; + text-transform: uppercase; + } + + #loading-page-message { + color: var(--fc-text); + font-size: 15px; + line-height: 1.7; + max-width: 30rem; + text-align: center; + } + + #sidebar { + background: + linear-gradient(180deg, rgba(10, 22, 40, 0.98), rgba(17, 29, 51, 0.98)), + url("/packages/thelounge-theme-flowercore/bluejay-bg.svg"); + border-right: 1px solid var(--fc-border); + color: #d5e3f5; + } + + #sidebar .logo-container { + padding: 20px 14px 8px; + } + + #sidebar .logo-container::before { + content: ""; + display: block; + width: 72px; + height: 72px; + margin: 0 auto 10px; + background: url("/packages/thelounge-theme-flowercore/bluejay-logo.svg") center / contain no-repeat; + filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.35)); + } + + #sidebar .logo-container::after { + content: "FlowerCore IRC"; + display: block; + color: #ffffff; + font-size: 18px; + font-weight: 700; + letter-spacing: 0.06em; + text-align: center; + text-transform: uppercase; + } + + #sidebar .network { + margin-bottom: 16px; + } + + .channel-list-item, + #footer button { + border-radius: 10px; + transition: background-color 0.2s ease, box-shadow 0.2s ease, color 0.2s ease; + } + + .channel-list-item:hover, + #footer button:hover { + background: rgba(43, 138, 255, 0.12); + color: #ffffff; + } + + .channel-list-item.active, + #footer button.active { + background: linear-gradient(90deg, rgba(43, 138, 255, 0.24), rgba(22, 40, 68, 0.92)); + box-shadow: inset 3px 0 0 var(--fc-gold); + color: #ffffff; + } + + .channel-list-item[data-type="lobby"] { + color: #8bc3ff; + } + + .channel-list-item .badge { + background: rgba(255, 255, 255, 0.08); + color: var(--fc-text-muted); + } + + .channel-list-item .badge.highlight { + background: var(--fc-gold); + color: #08111e; + font-weight: 700; + } + + #footer { + background: rgba(10, 22, 40, 0.92); + border-top: 1px solid var(--fc-border); + } + + #viewport .lt, + #viewport .rt, + #chat button.close, + #chat button.menu, + #chat button.mentions, + #chat button.search, + #form #submit, + #form #upload, + .password-container .reveal-password span { + color: #8bc3ff; + } + + #viewport .lt:hover, + #viewport .rt:hover, + #chat button.close:hover, + #chat button.menu:hover, + #chat button.mentions:hover, + #chat button.search:hover, + #form #submit:hover, + #form #upload:hover, + .password-container .reveal-password span:hover { + background: rgba(43, 138, 255, 0.16); + border-radius: 8px; + color: #ffffff; + opacity: 1; + } + + #chat .header { + background: linear-gradient(135deg, #0e1e36, #1a3a6a, #2b8aff); + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + color: #ffffff; + } + + .header .title, + .header .topic, + #chat .header button { + color: #ffffff; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2); + } + + #chat .messages { + background: + linear-gradient(180deg, rgba(17, 29, 51, 0.98), rgba(11, 21, 39, 0.98)), + radial-gradient(circle at top right, rgba(43, 138, 255, 0.08), transparent 35%); + } + + #chat .msg { + border-radius: 6px; + transition: background-color 0.2s ease; + } + + #chat .msg:hover { + background: rgba(255, 255, 255, 0.03); + } + + #chat .chat-view[data-type="channel"] .msg.highlight, + .mentions-popup .msg .content { + background: linear-gradient(90deg, rgba(43, 138, 255, 0.16), rgba(255, 179, 0, 0.1)); + box-shadow: inset 3px 0 0 var(--fc-gold); + } + + #chat .msg-statusmsg { + background: rgba(255, 179, 0, 0.18); + color: #ffe4a0; + } + + #chat .msg[data-type="monospace_block"] .text { + background: rgba(8, 17, 30, 0.94); + border: 1px solid rgba(43, 138, 255, 0.22); + border-radius: 10px; + box-shadow: inset 3px 0 0 var(--fc-gold); + color: var(--fc-text); + display: inline-block; + line-height: 1.7; + max-width: min(100%, 44rem); + padding: 10px 12px; + white-space: pre-wrap; + } + + #chat .msg[data-command="motd"] .text { + background: + linear-gradient(180deg, rgba(14, 30, 54, 0.96), rgba(8, 17, 30, 0.96)), + url("/packages/thelounge-theme-flowercore/bluejay-bg.svg"); + border-color: rgba(255, 179, 0, 0.28); + color: #f4f8ff; + } + + #chat .msg[data-command="motd"] .from { + color: #9dd3ff; + font-weight: 700; + } + + #chat .msg[data-command="motd"] a { + color: #8bc3ff; + font-weight: 700; + } + + #chat .userlist, + #form, + .mentions-popup, + .textcomplete-menu, + #context-menu { + background: rgba(17, 29, 51, 0.98); + border-color: var(--fc-border); + } + + #chat .userlist .count, + #chat .user-mode:before { + background: rgba(8, 17, 30, 0.95); + } + + .input, + #connect input, + #connect select, + #settings input, + #settings select, + #settings textarea, + #form #nick, + #chat .userlist .search, + form.message-search input, + .jump-to-input .input, + .password-container input { + background: rgba(8, 17, 30, 0.72); + border: 1px solid var(--fc-border); + border-radius: 10px; + color: var(--fc-text); + } + + #form { + border-top: 1px solid var(--fc-border); + padding: 8px; + } + + #form #nick { + color: #8bc3ff; + line-height: 28px; + } + + #form #input { + margin: 0 8px; + min-height: 36px; + padding: 8px 10px; + } + + ::placeholder, + .jump-to-input .input::placeholder, + form.message-search input::placeholder { + color: rgba(232, 237, 245, 0.45); + } + + .jump-to-input:before, + #chat .count:before { + color: rgba(232, 237, 245, 0.45); + } + + .btn { + background: linear-gradient(180deg, rgba(24, 62, 112, 0.28), rgba(14, 30, 54, 0.38)); + border-color: var(--fc-accent); + border-radius: 999px; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06); + color: var(--fc-text); + letter-spacing: 0.12em; + } + + .btn:hover, + .btn:focus, + .btn:disabled { + background: linear-gradient(180deg, #2b8aff, #1c6fe3); + color: #ffffff; + } + + .btn:active, + .btn:focus, + .input:focus { + box-shadow: 0 0 0 3px rgba(43, 138, 255, 0.26); + } + + #version-checker, + #settings .settings-sync-panel, + #connect .connect-sasl-external { + background: rgba(8, 17, 30, 0.78); + border: 1px solid var(--fc-border); + color: var(--fc-text); + } + + #version-checker.loading { + border-left: 3px solid var(--fc-accent); + color: #9dd3ff; + } + + #version-checker.up-to-date { + border-left: 3px solid var(--fc-success); + color: #87e9a9; + } + + #version-checker.new-packages, + #version-checker.new-version { + border-left: 3px solid var(--fc-gold); + color: #ffe4a0; + } + + #version-checker.error, + #settings .error, + #sign-in .error { + border-left: 3px solid var(--fc-danger); + color: #ffb3b3; + } + + #upload-progressbar { + box-shadow: 0 0 14px rgba(255, 179, 0, 0.75); + } + + ::-webkit-scrollbar:hover { + background-color: rgba(255, 255, 255, 0.04); + } + + ::-webkit-scrollbar-thumb:vertical { + background: linear-gradient(180deg, rgba(43, 138, 255, 0.72), rgba(30, 58, 95, 0.95)); + } + + ::-webkit-scrollbar-thumb:vertical:active { + background: linear-gradient(180deg, rgba(255, 179, 0, 0.85), rgba(43, 138, 255, 0.9)); + } + + @media (max-width: 768px) { + #sidebar { + box-shadow: 0 0 28px rgba(0, 0, 0, 0.5); + } + + #chat .header { + padding-right: 6px; + } + } + bluejay-logo.svg: | + + + + + + + + + + + + + + + + + bluejay-bg.svg: | + + + + + + + + + + + + + + + +--- +# UnrealIRCd configuration template (passwords replaced by placeholders) +apiVersion: v1 +kind: ConfigMap +metadata: + name: unrealircd-config-template + namespace: irc +data: + unrealircd.conf: | + /* BlueJay Lab IRC - UnrealIRCd 6.x config */ + /* Credentials injected from copied K8s secret at pod startup */ + + include "modules.default.conf"; + include "help/help.conf"; + include "operclass.default.conf"; + include "snomasks.default.conf"; + + loadmodule "cloak_sha256"; + + me { + name "irc.iamworkin.lan"; + info "BlueJay Lab IRC Server"; + sid 001; + } + + admin { + "BlueJay Lab IRC"; + "admin@iamwork.in"; + } + + class clients { + pingfreq 90; + maxclients 500; + sendq 200k; + recvq 8000; + } + + class opers { + pingfreq 90; + maxclients 50; + sendq 1M; + recvq 8000; + } + + class servers { + pingfreq 60; + connfreq 15; + maxclients 10; + sendq 20M; + } + + allow { + mask *; + class clients; + maxperip 5; + } + + listen { + ip *; + port 6667; + } + + listen { + ip *; + port 6697; + options { tls; } + tls-options { + certificate "/app/conf/tls/server.cert.pem"; + key "/app/conf/tls/server.key.pem"; + } + } + + listen { + ip *; + port 8067; + } + + oper bluejay { + mask *; + password "__OPER_PASSWORD__"; + operclass netadmin-with-override; + class opers; + } + + drpass { + restart "__OPER_PASSWORD__"; + die "__OPER_PASSWORD__"; + } + + link services.iamworkin.lan { + incoming { + mask *; + } + password "__LINK_PASSWORD__"; + class servers; + } + + ulines { + services.iamworkin.lan; + } + + log { + source { + all; + \\!debug; + } + destination { + channel "#ops"; + } + } + + set { + network-name "BlueJayIRC"; + default-server "irc.iamworkin.lan"; + services-server "services.iamworkin.lan"; + stats-server "stats.iamworkin.lan"; + help-channel "#general"; + cloak-keys { + "__CLOAK_KEY_1__"; + "__CLOAK_KEY_2__"; + "__CLOAK_KEY_3__"; + } + kline-address "admin@iamwork.in"; + maxchannelsperuser 25; + anti-flood { + everyone { + connect-flood 3:60; + } + } + options { + hide-ulines; + show-connect-info; + } + + /* TLS config */ + tls { + certificate "/app/conf/tls/server.cert.pem"; + key "/app/conf/tls/server.key.pem"; + trusted-ca-file "/etc/ssl/certs/ca-certificates.crt"; + } + + /* Allow plaintext for server-to-server links (Anope is internal) */ + plaintext-policy { + server allow; + } + } + ircd.motd: | + - BlueJay IRC - + Welcome to BlueJayIRC on iamworkin.lan. + + Web IRC: https://webirc.iamworkin.lan + Channels: #general, #ops, #alerts + + Keep it keyboard-first, practical, and kind. + Rehomed to GX10 (NVIDIA DGX Spark) K8s. +--- +# Anope configuration template (passwords replaced by placeholders) +apiVersion: v1 +kind: ConfigMap +metadata: + name: anope-config-template + namespace: irc +data: + services.conf: | + define + { + name = "services.host" + value = "services.iamworkin.lan" + } + + uplink + { + host = "unrealircd.irc.svc" + port = 8067 + password = "__LINK_PASSWORD__" + } + + serverinfo + { + name = "services.iamworkin.lan" + description = "BlueJay IRC Services" + pid = "/anope/data/services.pid" + motd = "/anope/data/services.motd" + } + + module { name = "unreal4" } + + networkinfo + { + networkname = "BlueJayIRC" + nicklen = 31 + userlen = 10 + hostlen = 64 + chanlen = 32 + } + + options + { + casemap = "ascii" + strictpasswords = yes + readtimeout = 5s + warningtimeout = 4h + } + + module { name = "enc_sha256" } + + /* Service pseudo-client definitions */ + service + { + nick = "NickServ" + user = "services" + host = "services.host" + gecos = "Nickname Registration Service" + } + + service + { + nick = "ChanServ" + user = "services" + host = "services.host" + gecos = "Channel Registration Service" + } + + service + { + nick = "OperServ" + user = "services" + host = "services.host" + gecos = "Operator Service" + } + + service + { + nick = "BotServ" + user = "services" + host = "services.host" + gecos = "Bot Service" + } + + service + { + nick = "HostServ" + user = "services" + host = "services.host" + gecos = "vHost Service" + } + + service + { + nick = "MemoServ" + user = "services" + host = "services.host" + gecos = "Memo Service" + } + + service + { + nick = "Global" + user = "services" + host = "services.host" + gecos = "Global Noticer" + } + + /* Module configurations */ + module + { + name = "nickserv" + client = "NickServ" + defaults = "kill_quick ns_secure ns_private hide_email" + registration = "none" + expire = 90d + } + + module { name = "ns_identify" } + module { name = "ns_register" } + module { name = "ns_set" } + module { name = "ns_drop" } + module { name = "ns_recover" } + module { name = "ns_info" } + module { name = "ns_list" } + module { name = "ns_access" } + module { name = "ns_group" } + + module + { + name = "chanserv" + client = "ChanServ" + defaults = "keeptopic peace cs_secure" + expire = 14d + } + + module { name = "cs_register" } + module { name = "cs_set" } + module { name = "cs_access" } + module { name = "cs_ban" } + module { name = "cs_kick" } + module { name = "cs_mode" } + module { name = "cs_topic" } + module { name = "cs_info" } + module { name = "cs_list" } + module { name = "cs_drop" } + + module + { + name = "operserv" + client = "OperServ" + } + + module { name = "os_akill" } + module { name = "os_mode" } + module { name = "os_kick" } + module { name = "os_kill" } + module { name = "os_list" } + module { name = "os_stats" } + module { name = "os_reload" } + module { name = "os_shutdown" } + + module + { + name = "botserv" + client = "BotServ" + defaults = "dontkickops fantasy greet" + } + + module { name = "bs_bot" } + module { name = "bs_assign" } + + module + { + name = "hostserv" + client = "HostServ" + } + + module { name = "hs_set" } + module { name = "hs_request" } + + module + { + name = "memoserv" + client = "MemoServ" + maxmemos = 20 + } + + module { name = "ms_send" } + module { name = "ms_read" } + module { name = "ms_del" } + module { name = "ms_list" } + + module + { + name = "global" + client = "Global" + } + + module { name = "gl_global" } + + opertype + { + name = "Services Root" + commands = "*" + privs = "*" + } + + oper + { + name = "bluejay" + type = "Services Root" + } + + module + { + name = "db_flatfile" + database = "anope.db" + fork = no + } + + log + { + target = "services.log" + admin = "*" + override = "chanserv/* nickserv/* operserv/*" + commands = "chanserv/* nickserv/* operserv/*" + servers = "*" + channels = "*" + users = "connect disconnect" + } +--- +# UnrealIRCd PVC (local-path on GX10) +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: unrealircd-data + namespace: irc +spec: + accessModes: [ReadWriteOnce] + storageClassName: local-path + resources: + requests: + storage: 1Gi +--- +# Anope PVC (local-path on GX10) — holds anope.db (NickServ/ChanServ registrations) +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: anope-data + namespace: irc +spec: + accessModes: [ReadWriteOnce] + storageClassName: local-path + resources: + requests: + storage: 1Gi +--- +# UnrealIRCd Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: unrealircd + namespace: irc + labels: + app: unrealircd +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: unrealircd + template: + metadata: + labels: + app: unrealircd + spec: + initContainers: + - name: inject-credentials + image: busybox:1.36 + command: ["sh", "-c"] + args: + - | + OPER_PW=$(cat /secrets/password) + LINK_PW=$(cat /secrets/Link-Password) + CLOAK_KEY_1=$(cat /cloak-secrets/cloak-key-1) + CLOAK_KEY_2=$(cat /cloak-secrets/cloak-key-2) + CLOAK_KEY_3=$(cat /cloak-secrets/cloak-key-3) + sed -e "s|__OPER_PASSWORD__|${OPER_PW}|g" \ + -e "s|__LINK_PASSWORD__|${LINK_PW}|g" \ + -e "s|__CLOAK_KEY_1__|${CLOAK_KEY_1}|g" \ + -e "s|__CLOAK_KEY_2__|${CLOAK_KEY_2}|g" \ + -e "s|__CLOAK_KEY_3__|${CLOAK_KEY_3}|g" \ + /config-template/unrealircd.conf > /injected-config/unrealircd.conf + echo "Credentials and cloak keys injected into unrealircd.conf" + volumeMounts: + - name: irc-credentials + mountPath: /secrets + readOnly: true + - name: unrealircd-cloak-keys + mountPath: /cloak-secrets + readOnly: true + - name: unrealircd-config-template + mountPath: /config-template + readOnly: true + - name: injected-config + mountPath: /injected-config + - name: copy-tls + image: busybox:1.36 + command: ["sh", "-c"] + args: + - | + cp /tls-secret/tls.crt /tls/server.cert.pem + cp /tls-secret/tls.key /tls/server.key.pem + chmod 644 /tls/server.cert.pem + chmod 644 /tls/server.key.pem + chown 1000:1000 /tls/server.cert.pem /tls/server.key.pem 2>/dev/null || true + chmod 777 /data + volumeMounts: + - name: irc-tls-secret + mountPath: /tls-secret + readOnly: true + - name: irc-tls + mountPath: /tls + - name: unrealircd-data + mountPath: /data + containers: + - name: unrealircd + image: localhost/fc-unrealircd:6.1.9.1-arm64 + imagePullPolicy: Never + ports: + - containerPort: 6667 + name: irc-plain + - containerPort: 6697 + name: irc-tls + - containerPort: 8067 + name: services-link + volumeMounts: + - name: injected-config + mountPath: /app/conf/unrealircd.conf + subPath: unrealircd.conf + - name: unrealircd-config-template + mountPath: /app/conf/ircd.motd + subPath: ircd.motd + readOnly: true + - name: unrealircd-data + mountPath: /app/data + - name: irc-tls + mountPath: /app/conf/tls + resources: + requests: + memory: 64Mi + cpu: 50m + limits: + memory: 256Mi + cpu: 250m + volumes: + - name: irc-credentials + secret: + secretName: irc-credentials + - name: unrealircd-cloak-keys + secret: + secretName: unrealircd-cloak-keys + - name: unrealircd-config-template + configMap: + name: unrealircd-config-template + - name: injected-config + emptyDir: {} + - name: unrealircd-data + persistentVolumeClaim: + claimName: unrealircd-data + - name: irc-tls-secret + secret: + secretName: irc-tls + - name: irc-tls + emptyDir: {} +--- +# Anope IRC Services Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: anope + namespace: irc + labels: + app: anope +spec: + replicas: 1 + selector: + matchLabels: + app: anope + template: + metadata: + labels: + app: anope + spec: + initContainers: + - name: inject-credentials + image: busybox:1.36 + command: ["sh", "-c"] + args: + - | + LINK_PW=$(cat /secrets/Link-Password) + sed -e "s|__LINK_PASSWORD__|${LINK_PW}|g" \ + /config-template/services.conf > /injected-config/services.conf + echo "Credentials injected into services.conf" + volumeMounts: + - name: irc-credentials + mountPath: /secrets + readOnly: true + - name: anope-config-template + mountPath: /config-template + readOnly: true + - name: injected-config + mountPath: /injected-config + - name: fix-perms + image: busybox:1.36 + command: ["sh", "-c"] + args: + - | + mkdir -p /data/db /data/logs /data/runtime + touch /data/anope.db /data/services.motd + chmod 666 /data/anope.db + chown -R 10000:10000 /data 2>/dev/null || chmod -R 777 /data + echo "Anope data dir prepared: $(ls -la /data/anope.db)" + volumeMounts: + - name: anope-data + mountPath: /data + containers: + - name: anope + image: anope/anope:2.0.15 + volumeMounts: + - name: injected-config + mountPath: /anope/conf/services.conf + subPath: services.conf + - name: anope-data + mountPath: /anope/data + workingDir: /anope/data + resources: + requests: + memory: 64Mi + cpu: 25m + limits: + memory: 128Mi + cpu: 100m + volumes: + - name: irc-credentials + secret: + secretName: irc-credentials + - name: anope-config-template + configMap: + name: anope-config-template + - name: injected-config + emptyDir: {} + - name: anope-data + persistentVolumeClaim: + claimName: anope-data +--- +# The Lounge web IRC Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: thelounge + namespace: irc + labels: + app: thelounge +spec: + replicas: 1 + selector: + matchLabels: + app: thelounge + template: + metadata: + labels: + app: thelounge + spec: + initContainers: + - name: install-flowercore-theme + image: ghcr.io/thelounge/thelounge:4.4.3 + command: + - sh + - -lc + - | + set -eu + THELOUNGE_HOME=/var/opt/thelounge thelounge install file:/flowercore-theme + volumeMounts: + - name: thelounge-config + mountPath: /var/opt/thelounge/config.js + subPath: config.js + - name: thelounge-packages + mountPath: /var/opt/thelounge/packages + - name: thelounge-flowercore-theme + mountPath: /flowercore-theme + containers: + - name: thelounge + image: ghcr.io/thelounge/thelounge:4.4.3 + ports: + - containerPort: 9000 + name: http + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 30 + periodSeconds: 20 + resources: + requests: + memory: 64Mi + cpu: 50m + limits: + memory: 256Mi + cpu: 250m + volumeMounts: + - name: thelounge-config + mountPath: /var/opt/thelounge/config.js + subPath: config.js + - name: thelounge-packages + mountPath: /var/opt/thelounge/packages + volumes: + - name: thelounge-config + configMap: + name: thelounge-config + - name: thelounge-packages + emptyDir: {} + - name: thelounge-flowercore-theme + configMap: + name: thelounge-flowercore-theme +--- +# UnrealIRCd internal Service (anope uplink 8067 + in-cluster 6667 for thelounge) +apiVersion: v1 +kind: Service +metadata: + name: unrealircd + namespace: irc +spec: + selector: + app: unrealircd + ports: + - port: 6667 + targetPort: 6667 + name: irc-plain + - port: 6697 + targetPort: 6697 + name: irc-tls + - port: 8067 + targetPort: 8067 + name: services-link +--- +# UnrealIRCd external LoadBalancer — exposes IRC TCP 6667/6697 on the GX10 PROD MetalLB pool. +# (Replaces OLD's Traefik irc/irctls entryPoints; GX10 Traefik has no such entryPoints.) +apiVersion: v1 +kind: Service +metadata: + name: unrealircd-lb + namespace: irc + annotations: + metallb.universe.tf/address-pool: prod-pool +spec: + type: LoadBalancer + loadBalancerIP: 10.0.57.204 + selector: + app: unrealircd + ports: + - port: 6667 + targetPort: 6667 + name: irc-plain + protocol: TCP + - port: 6697 + targetPort: 6697 + name: irc-tls + protocol: TCP +--- +# Anope Service +apiVersion: v1 +kind: Service +metadata: + name: anope + namespace: irc +spec: + selector: + app: anope + ports: + - port: 8067 + targetPort: 8067 + name: services-link +--- +# The Lounge web IRC Service +apiVersion: v1 +kind: Service +metadata: + name: thelounge + namespace: irc +spec: + selector: + app: thelounge + ports: + - port: 9000 + targetPort: 9000 + name: http +--- +# Traefik IngressRoute - The Lounge web IRC (webirc.iamworkin.lan) +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: webirc + namespace: irc +spec: + entryPoints: + - websecure + routes: + - match: Host(`webirc.iamworkin.lan`) + kind: Rule + services: + - name: thelounge + port: 9000 + tls: + secretName: webirc-tls diff --git a/apps/irc/irc.yaml b/apps/irc/irc.yaml index 26bc03a..7657682 100644 --- a/apps/irc/irc.yaml +++ b/apps/irc/irc.yaml @@ -685,9 +685,9 @@ data: stats-server "stats.iamworkin.lan"; help-channel "#general"; cloak-keys { - "ZWKeb8YevNiL45Xdh2p5u4tv2xksWgb8YPQSvmerBmNObyGbTDGnU4PNomZaLbZ1D9M2Cy6njM1XLJUkJhAx1oY3coBdZoPykEo7"; - "KqRaLeA6ijOnWDdCqYtJ6rb1VgR8lYnU9Sey7cbRhi3PsGzD5gZONJXyUdbJ7bD26QKCuiDydBsccUVKC3lYN0HJ9sGTlOYR3c2m"; - "2I4oopLDY79Fr4Mucy63EVOfkelVV23nESPWoqMnP1pUc8Yg0D4RK1mVtxyEhdTPpLFyKgG4fRlb6R33eHoQe7yi7moOu4W1Waw6"; + "__CLOAK_KEY_1__"; + "__CLOAK_KEY_2__"; + "__CLOAK_KEY_3__"; } kline-address "admin@iamwork.in"; maxchannelsperuser 25; @@ -1006,14 +1006,23 @@ spec: - | OPER_PW=$(cat /secrets/password) LINK_PW=$(cat /secrets/Link-Password) + CLOAK_KEY_1=$(cat /cloak-secrets/cloak-key-1) + CLOAK_KEY_2=$(cat /cloak-secrets/cloak-key-2) + CLOAK_KEY_3=$(cat /cloak-secrets/cloak-key-3) sed -e "s|__OPER_PASSWORD__|${OPER_PW}|g" \ - -e "s|__LINK_PASSWORD__|${LINK_PW}|g" \ - /config-template/unrealircd.conf > /injected-config/unrealircd.conf - echo "Credentials injected into unrealircd.conf" + -e "s|__LINK_PASSWORD__|${LINK_PW}|g" \ + -e "s|__CLOAK_KEY_1__|${CLOAK_KEY_1}|g" \ + -e "s|__CLOAK_KEY_2__|${CLOAK_KEY_2}|g" \ + -e "s|__CLOAK_KEY_3__|${CLOAK_KEY_3}|g" \ + /config-template/unrealircd.conf > /injected-config/unrealircd.conf + echo "Credentials and cloak keys injected into unrealircd.conf" volumeMounts: - name: irc-credentials mountPath: /secrets readOnly: true + - name: unrealircd-cloak-keys + mountPath: /cloak-secrets + readOnly: true - name: unrealircd-config-template mountPath: /config-template readOnly: true @@ -1071,6 +1080,9 @@ spec: - name: irc-credentials secret: secretName: irc-credentials + - name: unrealircd-cloak-keys + secret: + secretName: unrealircd-cloak-keys - name: unrealircd-config-template configMap: name: unrealircd-config-template