Wire IRC, mail, teamspeak to 1Password secrets

- IRC: OnePasswordItem CRD, ConfigMap templates with inject-credentials initContainers
- Mail: OnePasswordItem CRD, inject-accounts initContainer builds postfix-accounts.cf
- TeamSpeak: OnePasswordItem CRD, TS3SERVER_SERVERADMIN_PASSWORD from secret
- Zero hardcoded passwords remain in these manifests
This commit is contained in:
Andrew Stoltz
2026-03-09 20:55:45 -05:00
parent 3199c509c0
commit 2be7bf1279
3 changed files with 232 additions and 142 deletions

View File

@@ -1,5 +1,6 @@
# UnrealIRCd + Anope IRC Services # UnrealIRCd + Anope IRC Services
# ArgoCD managed - BlueJay Lab # ArgoCD managed - BlueJay Lab
# Credentials: 1Password → OnePasswordItem → K8s Secret → initContainer sed injection
--- ---
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
@@ -8,6 +9,15 @@ metadata:
labels: labels:
app.kubernetes.io/part-of: bluejay-infra app.kubernetes.io/part-of: bluejay-infra
--- ---
# 1Password → K8s Secret sync
apiVersion: onepassword.com/v1
kind: OnePasswordItem
metadata:
name: irc-credentials
namespace: irc
spec:
itemPath: "vaults/IAmWorkin/items/IRC UnrealIRCd"
---
# TLS Certificate for IRC # TLS Certificate for IRC
apiVersion: cert-manager.io/v1 apiVersion: cert-manager.io/v1
kind: Certificate kind: Certificate
@@ -22,17 +32,17 @@ spec:
dnsNames: dnsNames:
- irc.iamworkin.lan - irc.iamworkin.lan
--- ---
# UnrealIRCd configuration # UnrealIRCd configuration template (passwords replaced by placeholders)
apiVersion: v1 apiVersion: v1
kind: Secret kind: ConfigMap
metadata: metadata:
name: unrealircd-config name: unrealircd-config-template
namespace: irc namespace: irc
type: Opaque data:
stringData:
unrealircd.conf: | unrealircd.conf: |
/* BlueJay Lab IRC - UnrealIRCd 6.x config */ /* BlueJay Lab IRC - UnrealIRCd 6.x config */
/* Managed by ArgoCD */ /* Managed by ArgoCD */
/* Credentials injected from 1Password at pod startup */
include "modules.default.conf"; include "modules.default.conf";
include "help/help.conf"; include "help/help.conf";
@@ -101,21 +111,21 @@ stringData:
oper bluejay { oper bluejay {
mask *; mask *;
password "BlueJay-IRC-Oper-2026"; password "__OPER_PASSWORD__";
operclass netadmin-with-override; operclass netadmin-with-override;
class opers; class opers;
} }
drpass { drpass {
restart "BlueJay-IRC-Oper-2026"; restart "__OPER_PASSWORD__";
die "BlueJay-IRC-Oper-2026"; die "__OPER_PASSWORD__";
} }
link services.iamworkin.lan { link services.iamworkin.lan {
incoming { incoming {
mask *; mask *;
} }
password "BlueJay-Services-Link-2026"; password "__LINK_PASSWORD__";
class servers; class servers;
} }
@@ -126,7 +136,7 @@ stringData:
log { log {
source { source {
all; all;
\!debug; \\!debug;
} }
destination { destination {
channel "#ops"; channel "#ops";
@@ -169,14 +179,13 @@ stringData:
} }
} }
--- ---
# Anope configuration # Anope configuration template (passwords replaced by placeholders)
apiVersion: v1 apiVersion: v1
kind: Secret kind: ConfigMap
metadata: metadata:
name: anope-config name: anope-config-template
namespace: irc namespace: irc
type: Opaque data:
stringData:
services.conf: | services.conf: |
define define
{ {
@@ -188,7 +197,7 @@ stringData:
{ {
host = "unrealircd.irc.svc.cluster.local" host = "unrealircd.irc.svc.cluster.local"
port = 8067 port = 8067
password = "BlueJay-Services-Link-2026" password = "__LINK_PASSWORD__"
} }
serverinfo serverinfo
@@ -386,6 +395,26 @@ spec:
app: unrealircd app: unrealircd
spec: spec:
initContainers: initContainers:
- name: inject-credentials
image: busybox:1.36
command: ["sh", "-c"]
args:
- |
OPER_PW=$(cat /secrets/password)
LINK_PW=$(cat /secrets/Link-Password)
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"
volumeMounts:
- name: irc-credentials
mountPath: /secrets
readOnly: true
- name: unrealircd-config-template
mountPath: /config-template
readOnly: true
- name: injected-config
mountPath: /injected-config
- name: copy-tls - name: copy-tls
image: busybox:1.36 image: busybox:1.36
command: ["sh", "-c"] command: ["sh", "-c"]
@@ -416,7 +445,7 @@ spec:
- containerPort: 8067 - containerPort: 8067
name: services-link name: services-link
volumeMounts: volumeMounts:
- name: unrealircd-config - name: injected-config
mountPath: /app/conf/unrealircd.conf mountPath: /app/conf/unrealircd.conf
subPath: unrealircd.conf subPath: unrealircd.conf
- name: unrealircd-data - name: unrealircd-data
@@ -431,9 +460,14 @@ spec:
memory: 256Mi memory: 256Mi
cpu: 250m cpu: 250m
volumes: volumes:
- name: unrealircd-config - name: irc-credentials
secret: secret:
secretName: unrealircd-config secretName: irc-credentials
- name: unrealircd-config-template
configMap:
name: unrealircd-config-template
- name: injected-config
emptyDir: {}
- name: unrealircd-data - name: unrealircd-data
persistentVolumeClaim: persistentVolumeClaim:
claimName: unrealircd-data claimName: unrealircd-data
@@ -462,6 +496,24 @@ spec:
app: anope app: anope
spec: spec:
initContainers: 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 - name: fix-perms
image: busybox:1.36 image: busybox:1.36
command: ["sh", "-c"] command: ["sh", "-c"]
@@ -476,7 +528,7 @@ spec:
- name: anope - name: anope
image: anope/anope:latest image: anope/anope:latest
volumeMounts: volumeMounts:
- name: anope-config - name: injected-config
mountPath: /anope/conf/services.conf mountPath: /anope/conf/services.conf
subPath: services.conf subPath: services.conf
- name: anope-data - name: anope-data
@@ -489,9 +541,14 @@ spec:
memory: 128Mi memory: 128Mi
cpu: 100m cpu: 100m
volumes: volumes:
- name: anope-config - name: irc-credentials
secret: secret:
secretName: anope-config secretName: irc-credentials
- name: anope-config-template
configMap:
name: anope-config-template
- name: injected-config
emptyDir: {}
- name: anope-data - name: anope-data
persistentVolumeClaim: persistentVolumeClaim:
claimName: anope-data claimName: anope-data

View File

@@ -1,5 +1,6 @@
# docker-mailserver - Postfix + Dovecot + rspamd # docker-mailserver - Postfix + Dovecot + rspamd
# ArgoCD managed - BlueJay Lab # ArgoCD managed - BlueJay Lab
# Credentials: 1Password → OnePasswordItem CRD → K8s Secret
--- ---
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
@@ -8,17 +9,14 @@ metadata:
labels: labels:
app.kubernetes.io/part-of: bluejay-infra app.kubernetes.io/part-of: bluejay-infra
--- ---
# Mail accounts Secret (postfix-accounts.cf format: user@domain|{SHA512-CRYPT}hash) # 1Password → K8s Secret sync for mail credentials
apiVersion: v1 apiVersion: onepassword.com/v1
kind: Secret kind: OnePasswordItem
metadata: metadata:
name: mail-accounts name: mail-credentials
namespace: mail namespace: mail
type: Opaque spec:
stringData: itemPath: "vaults/IAmWorkin/items/Mail Postmaster"
postfix-accounts.cf: |
admin@iamwork.in|{SHA512-CRYPT}$6$1355214084ba403a$LPA.qkZLpv9RqMu8OenCrgYgyHbMwMIAYOuLrbNX/eeiaOj.8rtj9IlMeLDxSc6FdWK9N/PcNmBzV5fJL7IRn/
noreply@iamwork.in|{SHA512-CRYPT}$6$1355214084ba403a$LPA.qkZLpv9RqMu8OenCrgYgyHbMwMIAYOuLrbNX/eeiaOj.8rtj9IlMeLDxSc6FdWK9N/PcNmBzV5fJL7IRn/
--- ---
# Mail data PVC # Mail data PVC
apiVersion: v1 apiVersion: v1
@@ -65,6 +63,25 @@ spec:
app: mailserver app: mailserver
spec: spec:
hostname: mail hostname: mail
initContainers:
- name: inject-accounts
image: busybox:1.36
command:
- sh
- -c
- |
ADMIN_EMAIL=$(cat /credentials/Admin-Email)
ADMIN_HASH=$(cat /credentials/Admin-Hash)
NOREPLY_EMAIL=$(cat /credentials/Noreply-Email)
NOREPLY_HASH=$(cat /credentials/Noreply-Hash)
echo "${ADMIN_EMAIL}|${ADMIN_HASH}" > /accounts/postfix-accounts.cf
echo "${NOREPLY_EMAIL}|${NOREPLY_HASH}" >> /accounts/postfix-accounts.cf
volumeMounts:
- name: mail-credentials
mountPath: /credentials
readOnly: true
- name: mail-accounts-generated
mountPath: /accounts
containers: containers:
- name: mailserver - name: mailserver
image: docker.io/mailserver/docker-mailserver:latest image: docker.io/mailserver/docker-mailserver:latest
@@ -116,7 +133,7 @@ spec:
- name: mail-tls - name: mail-tls
mountPath: /etc/ssl/mail mountPath: /etc/ssl/mail
readOnly: true readOnly: true
- name: mail-accounts - name: mail-accounts-generated
mountPath: /tmp/docker-mailserver/postfix-accounts.cf mountPath: /tmp/docker-mailserver/postfix-accounts.cf
subPath: postfix-accounts.cf subPath: postfix-accounts.cf
readOnly: true readOnly: true
@@ -142,9 +159,11 @@ spec:
- name: mail-tls - name: mail-tls
secret: secret:
secretName: mail-tls secretName: mail-tls
- name: mail-accounts - name: mail-credentials
secret: secret:
secretName: mail-accounts secretName: mail-credentials
- name: mail-accounts-generated
emptyDir: {}
--- ---
# SMTP LoadBalancer Service (external) # SMTP LoadBalancer Service (external)
apiVersion: v1 apiVersion: v1

View File

@@ -1,108 +1,122 @@
# TeamSpeak 3 Server # TeamSpeak 3 Server
# ArgoCD managed - BlueJay Lab # ArgoCD managed - BlueJay Lab
--- ---
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: teamspeak name: teamspeak
labels: labels:
app.kubernetes.io/part-of: bluejay-infra app.kubernetes.io/part-of: bluejay-infra
--- ---
# TeamSpeak data PVC # 1Password secret sync - TeamSpeak credentials
apiVersion: v1 apiVersion: onepassword.com/v1
kind: PersistentVolumeClaim kind: OnePasswordItem
metadata: metadata:
name: teamspeak-data name: teamspeak-credentials
namespace: teamspeak namespace: teamspeak
spec: spec:
accessModes: [ReadWriteOnce] itemPath: "vaults/IAmWorkin/items/TeamSpeak 3"
resources: ---
requests: # TeamSpeak data PVC
storage: 1Gi apiVersion: v1
--- kind: PersistentVolumeClaim
# TeamSpeak 3 Deployment metadata:
apiVersion: apps/v1 name: teamspeak-data
kind: Deployment namespace: teamspeak
metadata: spec:
name: teamspeak accessModes: [ReadWriteOnce]
namespace: teamspeak resources:
labels: requests:
app: teamspeak storage: 1Gi
spec: ---
replicas: 1 # TeamSpeak 3 Deployment
strategy: apiVersion: apps/v1
type: Recreate kind: Deployment
selector: metadata:
matchLabels: name: teamspeak
app: teamspeak namespace: teamspeak
template: labels:
metadata: app: teamspeak
labels: spec:
app: teamspeak replicas: 1
spec: strategy:
containers: type: Recreate
- name: teamspeak selector:
image: teamspeak:latest matchLabels:
ports: app: teamspeak
- containerPort: 9987 template:
name: voice metadata:
protocol: UDP labels:
- containerPort: 30033 app: teamspeak
name: filetransfer spec:
protocol: TCP containers:
- containerPort: 10011 - name: teamspeak
name: serverquery image: teamspeak:latest
protocol: TCP ports:
env: - containerPort: 9987
- name: TS3SERVER_LICENSE name: voice
value: accept protocol: UDP
volumeMounts: - containerPort: 30033
- name: teamspeak-data name: filetransfer
mountPath: /var/ts3server protocol: TCP
resources: - containerPort: 10011
requests: name: serverquery
memory: 128Mi protocol: TCP
cpu: 50m env:
limits: - name: TS3SERVER_LICENSE
memory: 512Mi value: accept
cpu: 500m - name: TS3SERVER_SERVERADMIN_PASSWORD
readinessProbe: valueFrom:
tcpSocket: secretKeyRef:
port: 10011 name: teamspeak-credentials
initialDelaySeconds: 30 key: ServerQuery Password
periodSeconds: 10 volumeMounts:
livenessProbe: - name: teamspeak-data
tcpSocket: mountPath: /var/ts3server
port: 10011 resources:
initialDelaySeconds: 60 requests:
periodSeconds: 15 memory: 128Mi
volumes: cpu: 50m
- name: teamspeak-data limits:
persistentVolumeClaim: memory: 512Mi
claimName: teamspeak-data cpu: 500m
--- readinessProbe:
# TeamSpeak LoadBalancer Service tcpSocket:
apiVersion: v1 port: 10011
kind: Service initialDelaySeconds: 30
metadata: periodSeconds: 10
name: teamspeak livenessProbe:
namespace: teamspeak tcpSocket:
annotations: port: 10011
metallb.universe.tf/loadBalancerIPs: 10.0.56.205 initialDelaySeconds: 60
spec: periodSeconds: 15
type: LoadBalancer volumes:
selector: - name: teamspeak-data
app: teamspeak persistentVolumeClaim:
ports: claimName: teamspeak-data
- port: 9987 ---
targetPort: 9987 # TeamSpeak LoadBalancer Service
name: voice apiVersion: v1
protocol: UDP kind: Service
- port: 30033 metadata:
targetPort: 30033 name: teamspeak
name: filetransfer namespace: teamspeak
protocol: TCP annotations:
- port: 10011 metallb.universe.tf/loadBalancerIPs: 10.0.56.205
targetPort: 10011 spec:
name: serverquery type: LoadBalancer
protocol: TCP selector:
app: teamspeak
ports:
- port: 9987
targetPort: 9987
name: voice
protocol: UDP
- port: 30033
targetPort: 30033
name: filetransfer
protocol: TCP
- port: 10011
targetPort: 10011
name: serverquery
protocol: TCP