1.0.0 Release IaaS
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
#!/usr/sbin/nft -f
|
||||
flush ruleset
|
||||
|
||||
define NET4_SERVER = {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define PORTS_SSH = 22
|
||||
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
}
|
||||
chain postrouting {
|
||||
|
||||
}
|
||||
chain output {
|
||||
type nat hook output priority dstnat; policy accept;
|
||||
}
|
||||
}
|
||||
|
||||
table inet filter {
|
||||
chain input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
ct state invalid drop comment "deny invalid connection"
|
||||
ct state established, related accept comment "allow all connection already existing"
|
||||
iifname "lo" accept comment "allow local connection"
|
||||
meta l4proto { icmp, icmpv6 } accept comment "allow icmp connection"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > APP"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > APP"
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/sbin/nft -f
|
||||
flush ruleset
|
||||
|
||||
define NET4_SERVER = {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define PORTS_SSH = 22
|
||||
define PORTS_HTTP = 80
|
||||
define PORTS_HTTP_FORWARD = 2080
|
||||
define PORTS_HTTPS = 443
|
||||
define PORTS_HTTPS_FORWARD = 2443
|
||||
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
tcp dport $PORTS_HTTP dnat to :$PORTS_HTTP_FORWARD comment "dnat http ports to $PORTS_HTTP_FORWARD"
|
||||
tcp dport $PORTS_HTTPS dnat to :$PORTS_HTTPS_FORWARD comment "dnat https ports to $PORTS_HTTPS_FORWARD"
|
||||
}
|
||||
chain postrouting {
|
||||
|
||||
}
|
||||
chain output {
|
||||
type nat hook output priority dstnat; policy accept;
|
||||
oifname "lo" tcp dport $PORTS_HTTP dnat to :$PORTS_HTTP_FORWARD comment "dnat http ports to $PORTS_HTTP_FORWARD out of LOCALHOST"
|
||||
oifname "lo" tcp dport $PORTS_HTTPS dnat to :$PORTS_HTTPS_FORWARD comment "dnat https ports to $PORTS_HTTPS_FORWARD out of LOCALHOST"
|
||||
}
|
||||
}
|
||||
|
||||
table inet filter {
|
||||
chain input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
ct state invalid drop comment "deny invalid connection"
|
||||
ct state established, related accept comment "allow all connection already existing"
|
||||
iifname "lo" accept comment "allow local connection: AUTH > AUTH"
|
||||
meta l4proto { icmp, icmpv6 } accept comment "allow icmp connection: AUTH"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > AUTH"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > AUTH"
|
||||
tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv4, 6 http connection: > AUTH"
|
||||
tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv4, 6 https connection: > AUTH"
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
# localhost
|
||||
127.0.0.1 {{ node['local_san'] }}
|
||||
::1 {{ node['local_san'] }}
|
||||
{% if node['name'] == 'console' %}
|
||||
# Hosts IPv4
|
||||
{{ hostvars['fw']['network4']['firewall']['server'] }} fw.ilnmors.internal
|
||||
{{ hostvars['fw']['network4']['vmm']['client'] }} init.vmm.ilnmors.internal
|
||||
{{ hostvars['fw']['network4']['vmm']['server'] }} vmm.ilnmors.internal
|
||||
{{ hostvars['fw']['network4']['infra']['server'] }} infra.ilnmors.internal
|
||||
{{ hostvars['fw']['network4']['auth']['server'] }} auth.ilnmors.internal
|
||||
{{ hostvars['fw']['network4']['app']['server'] }} app.ilnmors.internal
|
||||
# Hosts IPv6
|
||||
{{ hostvars['fw']['network6']['firewall']['server'] }} fw.ilnmors.internal
|
||||
{{ hostvars['fw']['network6']['vmm']['client'] }} init.vmm.ilnmors.internal
|
||||
{{ hostvars['fw']['network6']['vmm']['server'] }} vmm.ilnmors.internal
|
||||
{{ hostvars['fw']['network6']['infra']['server'] }} infra.ilnmors.internal
|
||||
{{ hostvars['fw']['network6']['auth']['server'] }} auth.ilnmors.internal
|
||||
{{ hostvars['fw']['network6']['app']['server'] }} app.ilnmors.internal
|
||||
{% else %}
|
||||
# IPv4
|
||||
# Crowdsec, blocky, bind(fw)
|
||||
{{ hostvars['fw']['network4']['firewall']['server'] }} ntp.ilnmors.internal crowdsec.ilnmors.internal
|
||||
{{ hostvars['fw']['network4']['blocky']['server'] }} blocky.ilnmors.internal
|
||||
{{ hostvars['fw']['network4']['bind']['server'] }} bind.ilnmors.internal
|
||||
# DB, LDAP, CA, Prometheus, Loki, mail (infra)
|
||||
{{ hostvars['fw']['network4']['infra']['server'] }} postgresql.ilnmors.internal ldap.ilnmors.internal prometheus.ilnmors.internal loki.ilnmors.internal mail.ilnmors.internal ca.ilnmors.internal
|
||||
# IPv6
|
||||
# Crowdsec, blocky, bind(fw)
|
||||
{{ hostvars['fw']['network6']['firewall']['server'] }} ntp.ilnmors.internal crowdsec.ilnmors.internal
|
||||
{{ hostvars['fw']['network6']['blocky']['server'] }} blocky.ilnmors.internal
|
||||
{{ hostvars['fw']['network6']['bind']['server'] }} bind.ilnmors.internal
|
||||
# DB, LDAP, CA, Prometheus, Loki, mail (infra)
|
||||
{{ hostvars['fw']['network6']['infra']['server'] }} postgresql.ilnmors.internal ldap.ilnmors.internal prometheus.ilnmors.internal loki.ilnmors.internal mail.ilnmors.internal ca.ilnmors.internal
|
||||
{% endif %}
|
||||
@@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
MACAddress={{ hostvars[target_vm]['vm']['lan_mac'] }}
|
||||
|
||||
[Link]
|
||||
Name=eth0
|
||||
@@ -0,0 +1,13 @@
|
||||
[Match]
|
||||
Name=eth0
|
||||
|
||||
[Network]
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4'][target_vm]['server'] }}/24
|
||||
Gateway={{ hostvars['fw']['network4']['firewall']['server'] }}
|
||||
DNS={{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
# IPv6
|
||||
IPv6AcceptRA=false
|
||||
Address={{ hostvars['fw']['network6'][target_vm]['server'] }}/64
|
||||
Gateway={{ hostvars['fw']['network6']['firewall']['server'] }}
|
||||
DNS={{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
@@ -0,0 +1,6 @@
|
||||
[Resolve]
|
||||
{% if node['name'] in ['vmm', 'fw'] %}
|
||||
DNS=1.1.1.2 1.0.0.2
|
||||
DNS=2606:4700:4700::1112 2606:4700:4700::1002
|
||||
{% endif %}
|
||||
cache=false
|
||||
@@ -0,0 +1,2 @@
|
||||
HostKey /etc/ssh/ssh_host_ed25519_key
|
||||
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
|
||||
@@ -0,0 +1 @@
|
||||
PermitRootLogin no
|
||||
@@ -0,0 +1 @@
|
||||
TrustedUserCAKeys /etc/ssh/local_ssh_ca.pub
|
||||
@@ -0,0 +1,3 @@
|
||||
[Time]
|
||||
NTP=ntp.ilnmors.internal
|
||||
FallbackNTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org
|
||||
@@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
MACAddress={{ hostvars['fw']['vm']['wan_mac'] }}
|
||||
|
||||
[Link]
|
||||
Name=wan
|
||||
@@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
MACAddress={{ hostvars['fw']['vm']['lan_mac'] }}
|
||||
|
||||
[Link]
|
||||
Name=client
|
||||
@@ -0,0 +1,6 @@
|
||||
[NetDev]
|
||||
Name=server
|
||||
Kind=vlan
|
||||
|
||||
[VLAN]
|
||||
Id=10
|
||||
@@ -0,0 +1,6 @@
|
||||
[NetDev]
|
||||
Name=user
|
||||
Kind=vlan
|
||||
|
||||
[VLAN]
|
||||
Id=20
|
||||
@@ -0,0 +1,16 @@
|
||||
[Match]
|
||||
Name=wan
|
||||
|
||||
[Network]
|
||||
DHCP=true
|
||||
IPv6AcceptRA=true
|
||||
IPForward=true
|
||||
RequiredForOnline=false
|
||||
|
||||
[DHCPv4]
|
||||
UseDNS=false
|
||||
|
||||
[DHCPv6]
|
||||
WithoutRA=solicit
|
||||
PrefixDelegationHint=yes
|
||||
UseDNS=false
|
||||
@@ -0,0 +1,16 @@
|
||||
[Match]
|
||||
Name=client
|
||||
|
||||
[Network]
|
||||
# General
|
||||
IPForward=true
|
||||
IPv6SendRA=false
|
||||
IPv6AcceptRA=false
|
||||
VLAN=server
|
||||
VLAN=user
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4']['firewall']['client'] }}/24
|
||||
DNS={{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
# IPv6
|
||||
Address={{ hostvars['fw']['network6']['firewall']['client'] }}/64
|
||||
DNS={{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
@@ -0,0 +1,24 @@
|
||||
[Match]
|
||||
Name=server
|
||||
|
||||
[Network]
|
||||
IPForward=true
|
||||
IPv6SendRA=false
|
||||
IPv6AcceptRA=false
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4']['firewall']['server'] }}/24
|
||||
DNS={{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
# IPv6
|
||||
Address={{ hostvars['fw']['network6']['firewall']['server'] }}/64
|
||||
DNS={{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
|
||||
[Address]
|
||||
Address={{ hostvars['fw']['network4']['blocky']['server'] }}/24
|
||||
[Address]
|
||||
Address={{ hostvars['fw']['network4']['bind']['server'] }}/24
|
||||
[Address]
|
||||
Address={{ hostvars['fw']['network6']['blocky']['server'] }}/64
|
||||
PreferredLifetime=0
|
||||
[Address]
|
||||
Address={{ hostvars['fw']['network6']['bind']['server'] }}/64
|
||||
PreferredLifetime=0
|
||||
@@ -0,0 +1,25 @@
|
||||
[Match]
|
||||
Name=user
|
||||
|
||||
[Network]
|
||||
IPForward=true
|
||||
IPv6PrefixDelegation=true
|
||||
IPv6SendRA=true
|
||||
IPv6SendRAExtension=false
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4']['firewall']['user'] }}/24
|
||||
DNS={{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
|
||||
[IPv6PrefixDelegation]
|
||||
SubnetId=20
|
||||
# A-Flag: Enable SLAAC
|
||||
AddressAutoconfiguration=true
|
||||
OnLink=true
|
||||
|
||||
[IPv6SendRA]
|
||||
# M-Flag: Client IP from DHCPv6
|
||||
Managed=false
|
||||
# O-Flag: Other information form DHCPv6
|
||||
OtherInformation=false
|
||||
EmitDNS=true
|
||||
DNS={{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
@@ -0,0 +1,186 @@
|
||||
#!/usr/sbin/nft -f
|
||||
# Convention
|
||||
# iifname oifname saddr daddr proto dport ct state action / Ellipsis if you can something
|
||||
flush ruleset
|
||||
|
||||
define IF_WAN = "wan"
|
||||
define IF_CLIENT = "client"
|
||||
define IF_SERVER = "server"
|
||||
define IF_USER = "user"
|
||||
define IF_WG = "wg0"
|
||||
|
||||
define NET4_CLIENT = {{ hostvars['fw']['network4']['subnet']['client'] }}
|
||||
define NET4_SERVER = {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
define NET4_USER = {{ hostvars['fw']['network4']['subnet']['user'] }}
|
||||
define NET4_WG = {{ hostvars['fw']['network4']['subnet']['wg'] }}
|
||||
define NET4_LLA = {{ hostvars['fw']['network4']['subnet']['lla'] }}
|
||||
define NET4_RFC1918 = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }
|
||||
|
||||
define NET6_CLIENT = {{ hostvars['fw']['network6']['subnet']['client'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
define NET6_WG = {{ hostvars['fw']['network6']['subnet']['wg'] }}
|
||||
define NET6_LLA = {{ hostvars['fw']['network6']['subnet']['lla'] }}
|
||||
|
||||
define HOSTS4_FW = { {{ hostvars['fw']['network4']['firewall'].values() | join(', ') }} }
|
||||
define HOSTS4_BLOCKY = {{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
define HOSTS4_BIND = {{ hostvars['fw']['network4']['bind']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS4_VMM = { {{ hostvars['fw']['network4']['vmm'].values() | join(', ') }} }
|
||||
define HOSTS4_INFRA = {{ hostvars['fw']['network4']['infra']['server'] }}
|
||||
define HOSTS4_AUTH = {{ hostvars['fw']['network4']['auth']['server'] }}
|
||||
define HOSTS4_APP = {{ hostvars['fw']['network4']['app']['server'] }}
|
||||
define HOSTS4_NAS = {{ hostvars['fw']['network4']['nas']['client'] }}
|
||||
|
||||
define HOSTS6_FW = { {{ hostvars['fw']['network6']['firewall'].values() | join(', ') }} }
|
||||
define HOSTS6_BLOCKY = {{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
define HOSTS6_BIND = {{ hostvars['fw']['network6']['bind']['server'] }}
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_VMM = { {{ hostvars['fw']['network6']['vmm'].values() | join(', ') }} }
|
||||
define HOSTS6_INFRA = {{ hostvars['fw']['network6']['infra']['server'] }}
|
||||
define HOSTS6_AUTH = {{ hostvars['fw']['network6']['auth']['server'] }}
|
||||
define HOSTS6_APP = {{ hostvars['fw']['network6']['app']['server'] }}
|
||||
define HOSTS6_NAS = {{ hostvars['fw']['network6']['nas']['client'] }}
|
||||
|
||||
define PORTS_SSH = 22
|
||||
define PORTS_WEB = { 80, 443 }
|
||||
define PORTS_DHCP = { 67, 68, 546, 547 }
|
||||
define PORTS_DNS = 53
|
||||
define PORTS_NTP = 123
|
||||
define PORTS_VPN = 11290
|
||||
define PORTS_CROWDSEC = 8080
|
||||
define PORTS_NAS = { 5000, 5001 }
|
||||
define PORTS_KOPIA = 51515
|
||||
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
# After prerouting, accept forward chain WAN
|
||||
iifname $IF_WAN meta nfproto ipv4 tcp dport $PORTS_WEB dnat to $HOSTS4_AUTH comment "DNAT44 ipv4 web connection: WAN > FW > SERVER AUTH"
|
||||
iifname $IF_WAN meta nfproto ipv6 tcp dport $PORTS_WEB dnat to $HOSTS6_AUTH comment "DNAT66 ipv6 web connection: WAN > FW > SERVER AUTH"
|
||||
}
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority srcnat; policy accept;
|
||||
# Masquerade the packet
|
||||
oifname $IF_WAN meta nfproto ipv4 masquerade comment "masquerade ipv4 wan connection: > FW > WAN"
|
||||
# $IF_USER uses GUA on IPv6
|
||||
iifname { $IF_CLIENT, $IF_SERVER, $IF_WG } oifname $IF_WAN meta nfproto ipv6 masquerade comment "masquerade ipv6 wan connection: CLIENT/SERVER/WG > FW > WAN"
|
||||
}
|
||||
chain output {
|
||||
}
|
||||
}
|
||||
|
||||
table inet filter {
|
||||
set crowdsec-blacklists {
|
||||
type ipv4_addr
|
||||
flags timeout
|
||||
}
|
||||
set crowdsec6-blacklists {
|
||||
type ipv6_addr
|
||||
flags timeout
|
||||
}
|
||||
chain global {
|
||||
# invalid packets
|
||||
ct state invalid drop comment "deny invalid connection"
|
||||
# crowdsec
|
||||
ip saddr @crowdsec-blacklists counter drop comment "deny all crowdsec blacklist"
|
||||
ip6 saddr @crowdsec6-blacklists counter drop comment "deny all ipv6 crowdsec blacklist"
|
||||
# fw
|
||||
ct state established, related accept comment "allow all connection already existing"
|
||||
ip6 saddr $NET6_LLA return comment "return ipv6 linklocaladdress to input and forward chain"
|
||||
iifname $IF_WAN tcp dport $PORTS_SSH drop comment "deny ssh connection: WAN !> "
|
||||
iifname $IF_WAN udp dport $PORTS_DNS drop comment "deny udp dns connection: WAN !> "
|
||||
iifname $IF_WAN tcp dport $PORTS_DNS drop comment "deny tcp dns connection: WAN !> "
|
||||
iifname $IF_WAN icmp type echo-request drop comment "deny icmp echo connection (Ping): WAN !>"
|
||||
iifname $IF_WAN icmpv6 type echo-request drop comment "deny icmpv6 echo connection (Ping): WAN !>"
|
||||
iifname $IF_WAN meta l4proto { icmp, icmpv6 } accept comment "allow icmp, icmpv6 connection: WAN >"
|
||||
iifname $IF_WAN ip saddr $NET4_RFC1918 drop comment "deny ipv4 all connection: WAN RFC1918 !>"
|
||||
iifname $IF_WAN ip saddr $NET4_LLA drop comment "deny ipv4 all connection: WAN APIPA(bogon) !>"
|
||||
iifname { $IF_CLIENT, $IF_SERVER, $IF_USER } udp dport $PORTS_DHCP accept comment "allow dhcp4, dhcp6 connection: CLIENT/SERVER/USER > FW"
|
||||
iifname $IF_CLIENT ip saddr != $NET4_CLIENT drop comment "deny ipv4 all connection: CLIENT !CLIENT !>"
|
||||
iifname $IF_CLIENT ip6 saddr != $NET6_CLIENT drop comment "deny ipv6 all connection: CLIENT !CLIENT !>"
|
||||
iifname $IF_SERVER ip saddr != $NET4_SERVER drop comment "deny ipv4 all connection: SERVER !SERVER !>"
|
||||
iifname $IF_SERVER ip6 saddr != $NET6_SERVER drop comment "deny ipv6 all connection: SERVER !SERVER !>"
|
||||
# IF_USER uses GUA on ipv6, so ipv6 rule is not needed
|
||||
iifname $IF_USER ip saddr != $NET4_USER drop comment "deny ipv4 all connection: USER !USER !>"
|
||||
iifname $IF_WG ip saddr != $NET4_WG drop comment "deny all ipv4 connection: WG !WG !>"
|
||||
iifname $IF_WG ip6 saddr != $NET6_WG drop comment "deny all ipv6 connection: WG !WG !>"
|
||||
}
|
||||
chain input {
|
||||
type filter hook input priority filter; policy drop;
|
||||
jump global comment "set global condition"
|
||||
iifname "lo" accept comment "allow local connection: FW > FW"
|
||||
udp dport $PORTS_VPN accept comment "allow vpn connection: > FW"
|
||||
iifname { $IF_CLIENT, $IF_SERVER, $IF_USER, $IF_WG } meta l4proto { icmp, icmpv6 } accept comment "allow icmp, icmpv6 connection: CLIENT/SERVER/USER/WG > FW"
|
||||
iifname { $IF_CLIENT, $IF_SERVER, $IF_USER, $IF_WG } udp dport $PORTS_NTP accept comment "allow ntp connection: CLIENT/SERVER/USER/WG > FW"
|
||||
# Global chain contains "WAN !> :SSH_PORT"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > FW"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > FW"
|
||||
ip saddr { $HOSTS4_VMM, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv4 crowdsec lapi connection: SERVER > FW"
|
||||
ip6 saddr { $HOSTS6_VMM, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv6 crowdsec lapi connection: SERVER > FW"
|
||||
# Global chain contains "WAN !> :DNS_PORT"
|
||||
ip daddr $HOSTS4_BLOCKY udp dport $PORTS_DNS accept comment "allow ipv4 udp dns connection: !WAN > SERVER BLOCKY(FW)"
|
||||
ip daddr $HOSTS4_BLOCKY tcp dport $PORTS_DNS accept comment "allow ipv4 tcp dns connection: !WAN > SERVER BLOCKY(FW)"
|
||||
ip6 daddr $HOSTS6_BLOCKY udp dport $PORTS_DNS accept comment "allow ipv6 udp dns connection: !WAN > SERVER BLOCKY(FW)"
|
||||
ip6 daddr $HOSTS6_BLOCKY tcp dport $PORTS_DNS accept comment "allow ipv6 tcp dns connection: !WAN > SERVER BLOCKY(FW)"
|
||||
ip saddr { $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } ip daddr $HOSTS4_BIND udp dport $PORTS_DNS accept comment "allow ipv4 udp dns connection (nsupdate): SERVER INFRA/AUTH/APP > BIND9(FW)"
|
||||
ip saddr { $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } ip daddr $HOSTS4_BIND tcp dport $PORTS_DNS accept comment "allow ipv4 tcp dns connection (nsupdate): SERVER INFRA/AUTH/APP > BIND9(FW)"
|
||||
ip6 saddr { $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } ip6 daddr $HOSTS6_BIND udp dport $PORTS_DNS accept comment "allow ipv6 udp dns connection (nsupdate): SERVER INFRA/AUTH/APP > BIND9(FW)"
|
||||
ip6 saddr { $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } ip6 daddr $HOSTS6_BIND tcp dport $PORTS_DNS accept comment "allow ipv6 tcp dns connection (nsupdate): SERVER INFRA/AUTH/APP > BIND9(FW)"
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy drop;
|
||||
|
||||
jump global comment "set global condition"
|
||||
# ICMP
|
||||
ip saddr $HOSTS4_CONSOLE meta l4proto icmp accept comment "allow icmp connection: CONSOLE > FW >"
|
||||
ip6 saddr $HOSTS6_CONSOLE meta l4proto icmpv6 accept comment "allow icmpv6 connection: CONSOLE > FW >"
|
||||
# SSH connection
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > FW >"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > FW >"
|
||||
# Reverse proxy (WAN)
|
||||
oifname $IF_SERVER ip daddr $HOSTS4_AUTH tcp dport $PORTS_WEB accept comment "allow ipv4 web connection: > FW > SERVER AUTH"
|
||||
oifname $IF_SERVER ip6 daddr $HOSTS6_AUTH tcp dport $PORTS_WEB accept comment "allow ipv6 web connection: > FW > SERVER AUTH"
|
||||
# Reverse proxy (SERVER)
|
||||
oifname $IF_SERVER ip saddr $HOSTS4_CONSOLE ip daddr { $HOSTS4_INFRA, $HOSTS4_APP } tcp dport $PORTS_WEB accept comment "allow ipv4 web connection: CONSOLE > FW > SERVER INFRA/APP"
|
||||
oifname $IF_SERVER ip6 saddr $HOSTS6_CONSOLE ip6 daddr { $HOSTS6_INFRA, $HOSTS6_APP } tcp dport $PORTS_WEB accept comment "allow ipv6 web connection: CONSOLE > FW > SERVER INFRA/APP"
|
||||
# Kopia/NAS Console > NAS
|
||||
oifname $IF_CLIENT ip saddr $HOSTS4_CONSOLE ip daddr $HOSTS4_NAS tcp dport { $PORTS_NAS, $PORTS_KOPIA } accept comment "allow ipv4 web connection (DSM, KOPIA): CONSOLE > FW > CLIENT NAS"
|
||||
oifname $IF_CLIENT ip6 saddr $HOSTS6_CONSOLE ip6 daddr $HOSTS6_NAS tcp dport { $PORTS_NAS, $PORTS_KOPIA } accept comment "allow ipv6 web connection (DSM, KOPIA): CONSOLE > FW > CLIENT NAS"
|
||||
|
||||
iifname $IF_WAN jump wan comment "set WAN interface rules"
|
||||
iifname $IF_CLIENT jump client comment "set CLIENT interface rules"
|
||||
iifname $IF_SERVER jump server comment "set SERVER interface rules"
|
||||
iifname $IF_USER jump user comment "set USER interface rules"
|
||||
iifname $IF_WG jump wg comment "set WG interface rules"
|
||||
}
|
||||
chain wan {
|
||||
return
|
||||
}
|
||||
chain client {
|
||||
oifname $IF_WAN ip saddr { $HOSTS4_CONSOLE, $HOSTS4_NAS } accept comment "allow ipv4 internet connection: CLIENT CONSOLE/NAS > FW > WAN"
|
||||
oifname $IF_WAN ip6 saddr { $HOSTS6_CONSOLE, $HOSTS6_NAS } accept comment "allow ipv6 internet connection: CLIENT CONSOLE/NAS > FW > WAN"
|
||||
return
|
||||
}
|
||||
chain server {
|
||||
# reverse proxy AUTH > NAS
|
||||
oifname $IF_CLIENT ip saddr $HOSTS4_AUTH ip daddr $HOSTS4_NAS tcp dport $PORTS_NAS accept comment "allow ipv4 web connection(DSM): SERVER AUTH > FW > CLIENT NAS"
|
||||
oifname $IF_CLIENT ip6 saddr $HOSTS6_AUTH ip6 daddr $HOSTS6_NAS tcp dport $PORTS_NAS accept comment "allow ipv6 web connection(DSM): SERVER AUTH > FW > CLIENT NAS"
|
||||
# Kopia INFRA, APP > NAS
|
||||
oifname $IF_CLIENT ip saddr { $HOSTS4_INFRA, $HOSTS4_APP } ip daddr $HOSTS4_NAS tcp dport $PORTS_KOPIA accept comment "allow ipv4 web connection(kopia): SERVER INFRA/APP > FW > CLIENT NAS"
|
||||
oifname $IF_CLIENT ip6 saddr { $HOSTS6_INFRA, $HOSTS6_APP } ip6 daddr $HOSTS6_NAS tcp dport $PORTS_KOPIA accept comment "allow ipv6 web connection(kopia): SERVER INFRA/APP > FW > CLIENT NAS"
|
||||
oifname $IF_WAN ip saddr { $HOSTS4_VMM, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } accept comment "allow ipv4 internet connection: SERVER VMM/INFRA/AUTH/APP > FW > WAN"
|
||||
oifname $IF_WAN ip6 saddr { $HOSTS6_VMM, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } accept comment "allow ipv6 internet connection: SERVER VMM/INFRA/AUTH/APP > FW > WAN"
|
||||
return
|
||||
}
|
||||
chain user {
|
||||
oifname $IF_WAN accept comment "allow internet connection: USER > FW > WAN"
|
||||
return
|
||||
}
|
||||
chain wg {
|
||||
oifname $IF_WAN accept comment "allow internet connection: WG > FW > WAN"
|
||||
return
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority filter; policy accept;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[NetDev]
|
||||
Name=wg0
|
||||
Kind=wireguard
|
||||
[WireGuard]
|
||||
ListenPort=11290
|
||||
PrivateKey={{ hostvars['console']['wireguard']['server']['private_key'] }}
|
||||
[WireGuardPeer]
|
||||
PublicKey={{ hostvars['console']['wireguard']['console']['public_key'] }}
|
||||
PresharedKey={{ hostvars['console']['wireguard']['console']['preshared_key'] }}
|
||||
AllowedIPs={{ hostvars['fw']["network4"]["console"]["wg"] }}/32, {{ hostvars['fw']["network6"]["console"]["wg"] }}/128
|
||||
@@ -0,0 +1,6 @@
|
||||
[Match]
|
||||
Name=wg0
|
||||
[Network]
|
||||
Address={{ hostvars['fw']["network4"]["firewall"]["wg"] }}/24
|
||||
Address={{ hostvars['fw']["network6"]["firewall"]["wg"] }}/64
|
||||
IPForward=yes
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/usr/sbin/nft -f
|
||||
# Convention
|
||||
# iifname oifname saddr daddr proto dport ct state action / Ellipsis if you can something
|
||||
flush ruleset
|
||||
|
||||
define NET4_SERVER = {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define PORTS_SSH = 22
|
||||
define PORTS_DB = 5432
|
||||
define PORTS_CA = 9000
|
||||
define PORTS_LDAPS = 636
|
||||
define PORTS_LDAPS_FORWARD = 6360
|
||||
define PORTS_HTTP = 80
|
||||
define PORTS_HTTP_FORWARD = 2080
|
||||
define PORTS_HTTPS = 443
|
||||
define PORTS_HTTPS_FORWARD = 2443
|
||||
define PORTS_PROMETHEUS = 9090
|
||||
define PORTS_LOKI = 3100
|
||||
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
tcp dport $PORTS_HTTP dnat to :$PORTS_HTTP_FORWARD comment "DNAT http ports to $PORTS_HTTP_FORWARD"
|
||||
tcp dport $PORTS_HTTPS dnat to :$PORTS_HTTPS_FORWARD comment "DNAT https ports to $PORTS_HTTPS_FORWARD"
|
||||
tcp dport $PORTS_LDAPS dnat to :$PORTS_LDAPS_FORWARD comment "DNAT ldaps ports to $PORTS_LDAPS_FORWARD"
|
||||
}
|
||||
chain postrouting {
|
||||
|
||||
}
|
||||
chain output {
|
||||
type nat hook output priority dstnat; policy accept;
|
||||
oifname "lo" tcp dport $PORTS_HTTP dnat to :$PORTS_HTTP_FORWARD comment "DNAT http ports to $PORTS_HTTP_FORWARD out of LOCALHOST"
|
||||
oifname "lo" tcp dport $PORTS_HTTPS dnat to :$PORTS_HTTPS_FORWARD comment "DNAT https ports to $PORTS_HTTPS_FORWARD out of LOCALHOST"
|
||||
oifname "lo" tcp dport $PORTS_LDAPS dnat to :$PORTS_LDAPS_FORWARD comment "DNAT ldaps ports to $PORTS_LDAPS_FORWARD out of LOCALHOST"
|
||||
}
|
||||
}
|
||||
|
||||
table inet filter {
|
||||
chain input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
ct state invalid drop comment "deny invalid connection"
|
||||
ct state established, related accept comment "allow all connection already existing"
|
||||
iifname "lo" accept comment "allow local connection: INFRA > INFRA"
|
||||
meta l4proto { icmp, icmpv6 } accept comment "allow icmp connection: > INFRA"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > INFRA"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_CA accept comment "allow ipv4 ca connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_CA accept comment "allow ipv6 ca connection: SERVER > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_DB accept comment "allow ipv4 db connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_DB accept comment "allow ipv6 db connection: SERVER > INFRA"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv4 http connection: CONSOLE > INFRA"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv6 http connection: CONSOLE > INFRA"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv4 https connection: CONSOLE > INFRA"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv6 https connection: CONSOLE > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_LDAPS_FORWARD ct original proto-dst $PORTS_LDAPS accept comment "allow ipv4 ldaps connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_LDAPS_FORWARD ct original proto-dst $PORTS_LDAPS accept comment "allow ipv6 ldaps connection: SERVER > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_PROMETHEUS accept comment "allow ipv4 prometheus connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_PROMETHEUS accept comment "allow ipv6 prometheus connection: SERVER > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_LOKI accept comment "allow ipv4 loki connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_LOKI accept comment "allow ipv6 loki connection: SERVER > INFRA"
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
MACAddress=c8:ff:bf:05:aa:b0
|
||||
|
||||
[Link]
|
||||
Name=eth0
|
||||
@@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
MACAddress=c8:ff:bf:05:aa:b1
|
||||
|
||||
[Link]
|
||||
Name=eth1
|
||||
@@ -0,0 +1,3 @@
|
||||
[NetDev]
|
||||
Name=br0
|
||||
Kind=bridge
|
||||
@@ -0,0 +1,7 @@
|
||||
[NetDev]
|
||||
Name=br1
|
||||
Kind=bridge
|
||||
|
||||
[Bridge]
|
||||
VLANFiltering=true
|
||||
DefaultPVID=1
|
||||
@@ -0,0 +1,6 @@
|
||||
[NetDev]
|
||||
Name=vlan1
|
||||
Kind=vlan
|
||||
|
||||
[VLAN]
|
||||
Id=1
|
||||
@@ -0,0 +1,6 @@
|
||||
[NetDev]
|
||||
Name=vlan10
|
||||
Kind=vlan
|
||||
|
||||
[VLAN]
|
||||
Id=10
|
||||
@@ -0,0 +1,6 @@
|
||||
[NetDev]
|
||||
Name=vlan20
|
||||
Kind=vlan
|
||||
|
||||
[VLAN]
|
||||
Id=20
|
||||
@@ -0,0 +1,6 @@
|
||||
[Match]
|
||||
Name=eth0
|
||||
|
||||
[Network]
|
||||
Bridge=br0
|
||||
LinkLocalAddressing=false
|
||||
@@ -0,0 +1,15 @@
|
||||
[Match]
|
||||
Name=eth1
|
||||
|
||||
[Network]
|
||||
Bridge=br1
|
||||
LinkLocalAddressing=false
|
||||
|
||||
[BridgeVLAN]
|
||||
VLAN=1
|
||||
PVID=true
|
||||
EgressUntagged=true
|
||||
|
||||
[BridgeVLAN]
|
||||
VLAN=10
|
||||
VLAN=20
|
||||
@@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
Name=br0
|
||||
|
||||
[Network]
|
||||
LinkLocalAddressing=false
|
||||
@@ -0,0 +1,17 @@
|
||||
[Match]
|
||||
Name=br1
|
||||
|
||||
[Network]
|
||||
VLAN=vlan1
|
||||
VLAN=vlan10
|
||||
VLAN=vlan20
|
||||
LinkLocalAddressing=false
|
||||
|
||||
[BridgeVLAN]
|
||||
VLAN=1
|
||||
PVID=yes
|
||||
EgressUntagged=true
|
||||
|
||||
[BridgeVLAN]
|
||||
VLAN=10
|
||||
VLAN=20
|
||||
@@ -0,0 +1,28 @@
|
||||
[Match]
|
||||
Name=vlan1
|
||||
|
||||
[Network]
|
||||
# IPv4
|
||||
Address=192.168.1.10/24
|
||||
# IPv6
|
||||
Address=fd00:1::10/64
|
||||
|
||||
[RoutingPolicyRule]
|
||||
From=192.168.1.10/32
|
||||
Table=1
|
||||
Priority=100
|
||||
|
||||
[Route]
|
||||
Destination=192.168.1.0/24
|
||||
Scope=link
|
||||
Table=1
|
||||
|
||||
[RoutingPolicyRule]
|
||||
From=fd00:1::10/128
|
||||
Table=61
|
||||
Priority=100
|
||||
|
||||
[Route]
|
||||
Destination=fd00:1::/64
|
||||
Scope=link
|
||||
Table=61
|
||||
@@ -0,0 +1,32 @@
|
||||
[Match]
|
||||
Name=vlan10
|
||||
[Network]
|
||||
RequiredForOnline=false
|
||||
# IPv4
|
||||
Address=192.168.10.10/24
|
||||
Gateway=192.168.10.1
|
||||
DNS=192.168.10.2
|
||||
# IPv6
|
||||
Address=fd00:10::10/64
|
||||
Gateway=fd00:10::1
|
||||
DNS=fd00:10::2
|
||||
|
||||
[RoutingPolicyRule]
|
||||
From=192.168.10.10/32
|
||||
Table=2
|
||||
Priority=100
|
||||
|
||||
[Route]
|
||||
Destination=0.0.0.0/0
|
||||
Gateway=192.168.10.1
|
||||
Table=2
|
||||
|
||||
[RoutingPolicyRule]
|
||||
From=fd00:10::10/128
|
||||
Table=62
|
||||
Priority=100
|
||||
|
||||
[Route]
|
||||
Destination=::/0
|
||||
Gateway=fd00:10::1
|
||||
Table=62
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/sbin/nft -f
|
||||
# Convention
|
||||
# iifname oifname saddr daddr proto dport ct state action / Ellipsis if you can something
|
||||
flush ruleset
|
||||
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define PORTS_SSH = 22
|
||||
|
||||
table inet filter {
|
||||
chain input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
ct state invalid drop comment "deny invalid connection"
|
||||
ct state established, related accept comment "allow all connection already existing"
|
||||
iifname "lo" accept comment "allow local connection"
|
||||
meta l4proto { icmp, icmpv6 } accept comment "allow icmp connection: > VMM"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > VMM"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > VMM"
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
creation_rules:
|
||||
- path_regex: secrets\.yaml$
|
||||
age: age120wuwcmsm845ztsvsz46pswj5je53uc2n35vadklrfqudu6cxuusxetk7y
|
||||
Binary file not shown.
Executable
+86
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
# edit_secret.sh /path/of/secret/secret.yaml
|
||||
|
||||
set -e
|
||||
|
||||
# Varibles
|
||||
KEY_PATH="$HOME/workspace/homelab/config/secrets"
|
||||
TMP_PATH="/run/user/$UID"
|
||||
SECRET_FILE="$1"
|
||||
|
||||
# Usage function
|
||||
usage() {
|
||||
echo "Usage: $0 \"/path/of/secret/secret.yaml\"" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Log function
|
||||
log() {
|
||||
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
local level="$1"
|
||||
local msg="$2"
|
||||
echo "time=\"$timestamp\" level=\"$level\" msg=\"$msg\" source=\"edit_secret.sh\"">&2
|
||||
}
|
||||
|
||||
# Secret file check
|
||||
if [ -z "$SECRET_FILE" -o ! -f "$SECRET_FILE" ]; then
|
||||
log "error" "Secret file path is required"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# age-key file check
|
||||
if [ ! -f "$KEY_PATH/age-key.gpg" ]; then
|
||||
log "error" "age key path is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependency check
|
||||
if ! command -v sops >/dev/null; then
|
||||
log "error" "sops is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v gpg >/dev/null; then
|
||||
log "error" "gnupg is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Cleanup function for trap
|
||||
cleanup() {
|
||||
if [ -f "$TMP_PATH/age-key" ]; then
|
||||
rm -f "$TMP_PATH/age-key"
|
||||
log "info" "age key is deleted"
|
||||
fi
|
||||
}
|
||||
|
||||
# Trap
|
||||
trap cleanup EXIT
|
||||
|
||||
# Get GPG password from prompt
|
||||
echo -n "Enter GPG passphrase: " >&2
|
||||
read -s GPG_PASSPHRASE
|
||||
echo "" >&2
|
||||
|
||||
# Decrypt age-key on the tmpfs (memory)
|
||||
echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 \
|
||||
--output "$TMP_PATH/age-key" \
|
||||
--decrypt "$KEY_PATH/age-key.gpg" &&\
|
||||
chmod 600 "$TMP_PATH/age-key"
|
||||
|
||||
# Unset environment varibles
|
||||
unset GPG_PASSPHRASE
|
||||
|
||||
# Check the key on memory
|
||||
if [ ! -f "$TMP_PATH/age-key" ]; then
|
||||
log "error" "age key does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Kill the gpg session value
|
||||
gpgconf --kill gpg-agent
|
||||
|
||||
# Open sops editor and delete the key
|
||||
SOPS_AGE_KEY_FILE="$TMP_PATH/age-key" sops "$SECRET_FILE"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,151 @@
|
||||
#!/bin/bash
|
||||
# extract_secret.sh /path/of/secret/secret.yaml [-n] (-f|-e <value>)
|
||||
|
||||
set -e
|
||||
|
||||
# Varibles
|
||||
KEY_PATH="$HOME/workspace/homelab/config/secrets"
|
||||
TMP_PATH="/run/user/$UID"
|
||||
SECRET_FILE="$1"
|
||||
VALUE=""
|
||||
TYPE=""
|
||||
NEWLINE="true"
|
||||
|
||||
# Remove $1 and shift $(n-1) < $n
|
||||
shift
|
||||
|
||||
# Usage function
|
||||
|
||||
usage () {
|
||||
echo "Usage: $0 \"/path/of/secret/secret.yaml\" [-n] (-f|-e \"yaml section name\")"
|
||||
echo "-n: remove the newline"
|
||||
echo "-f <type name>: Print secret file"
|
||||
echo "-e <type name>: Print secret env file"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Log function
|
||||
log() {
|
||||
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
local level="$1"
|
||||
local msg="$2"
|
||||
echo "time=\"$timestamp\" level=\"$level\" msg=\"$msg\" source=\"extract_secret.sh\"">&2
|
||||
}
|
||||
|
||||
# getops to get parameters
|
||||
while getopts "f:e:n" opt; do
|
||||
case $opt in
|
||||
f)
|
||||
VALUE="$OPTARG"
|
||||
TYPE="FILE"
|
||||
;;
|
||||
e)
|
||||
VALUE="$OPTARG"
|
||||
TYPE="ENV"
|
||||
;;
|
||||
n)
|
||||
NEWLINE="false"
|
||||
;;
|
||||
\?)
|
||||
log "error" "Invalid option: -$OPTARG"
|
||||
usage
|
||||
;;
|
||||
:)
|
||||
log "error" "Option -$OPTARG requires an argument"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Secret file check
|
||||
if [ -z "$SECRET_FILE" -o ! -f "$SECRET_FILE" ]; then
|
||||
log "error" "Secret file path is required"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# -f or -e option check
|
||||
if [ -z "$TYPE" ]; then
|
||||
log "error" "-f or -e option requires"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# age-key file check
|
||||
if [ ! -f "$KEY_PATH/age-key.gpg" ]; then
|
||||
log "error" "Key file is required: $KEY_PATH/age-key.gpg"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependency check
|
||||
if ! command -v sops >/dev/null; then
|
||||
log "error" "sops is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v gpg >/dev/null; then
|
||||
log "error" "gnupg is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Cleanup function for trap
|
||||
cleanup() {
|
||||
if [ -f "$TMP_PATH/age-key" ]; then
|
||||
rm -f "$TMP_PATH/age-key"
|
||||
log "info" "age-key was deleted"
|
||||
fi
|
||||
}
|
||||
|
||||
# Trap
|
||||
trap cleanup EXIT
|
||||
|
||||
# Get GPG password from prompt
|
||||
echo -n "Enter GPG passphrase: " >&2
|
||||
read -s GPG_PASSPHRASE
|
||||
echo "" >&2
|
||||
|
||||
# Decrypt age-key on the tmpfs (memory)
|
||||
echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 \
|
||||
--output "$TMP_PATH/age-key" \
|
||||
--decrypt "$KEY_PATH/age-key.gpg" &&\
|
||||
chmod 600 "$TMP_PATH/age-key"
|
||||
|
||||
# Unset environment varibles
|
||||
unset GPG_PASSPHRASE
|
||||
|
||||
# Check the key on memory
|
||||
if [ ! -f "$TMP_PATH/age-key" ]; then
|
||||
log "error" "age key file does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Kill the gpg session value
|
||||
gpgconf --kill gpg-agent
|
||||
|
||||
if [ "$TYPE" == "FILE" ]; then
|
||||
if RESULT=$(SOPS_AGE_KEY_FILE="$TMP_PATH/age-key" sops --decrypt --extract "[\"$VALUE\"]" --output-type binary "$SECRET_FILE") ; then
|
||||
if [ "$NEWLINE" == "true" ]; then
|
||||
echo "$RESULT"
|
||||
else
|
||||
echo -n "$RESULT"
|
||||
fi
|
||||
exit 0
|
||||
else
|
||||
log "error" "SOPS extract error"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$TYPE" == "ENV" ]; then
|
||||
if RESULT=$(SOPS_AGE_KEY_FILE="$TMP_PATH/age-key" sops --decrypt --extract "[\"$VALUE\"]" --output-type dotenv "$SECRET_FILE") ; then
|
||||
if [ "$NEWLINE" == "true" ]; then
|
||||
echo "$RESULT"
|
||||
else
|
||||
echo -n "$RESULT"
|
||||
fi
|
||||
exit 0
|
||||
else
|
||||
log "error" "SOPS extract error"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,205 @@
|
||||
#ENC[AES256_GCM,data:p5q9g2YX1hb7yIKFsuHhO6EVsTU00Q3JopqUX7Gr63z5SmQQaK2f+73FGXBjW5c=,iv:P895qJTjJioxM1OpXg7xTscA4UBQRyDxTUnHXb17dhA=,tag:TWmvv/0gD78mE0zbp4Av7w==,type:comment]
|
||||
#ENC[AES256_GCM,data:LHFLuYEf6f3spreglxE445d3BZeUfOlJSIKcqByoWePJ+BJcDi2VUKUQJBGz+KPYSFqBNlucgGdeXNajgeC0SgIkEWDi3Cg3ORX2RBE=,iv:A17KfTM9AxfAdOlCtpxOXRft6+2fYqNCEOSgaob8Upc=,tag:IZOzealCJ4M2KQuzSCek7Q==,type:comment]
|
||||
#
|
||||
#ENC[AES256_GCM,data:U/qLcosbBJIVoIv4d4Zjb+c=,iv:rdAsPzdZgu5UVxWTiOmYglCBWBsyq6HktO2+/Dqmudw=,tag:K7Kci7xGrRXCKsSG5UkHEA==,type:comment]
|
||||
sudo:
|
||||
password:
|
||||
console: ENC[AES256_GCM,data:RdvzU4VOU+ww1OVvLanD9KbCYom/yPHQ1DdjUBfG6l9nPHEapYqqvHpr6Oi3nDRfc2n5cR4R40i0DHCh01Eo,iv:X8RxKloim0jsDj8U/aY+rHARtrlTrvwNMqMcTmdPfes=,tag:eaMrWFdyU9jifh3SvBrE+A==,type:str]
|
||||
vmm: ENC[AES256_GCM,data:CqEAeHMgRkmsFYFGOyHic2TGYXlw/1VO4mMAaPSHqzGDoW6u6Gz29uho9EY=,iv:5fc0LkIQ/gVFTK7YEjnmA5ye2EEyh5/61VvTVarGOQA=,tag:yLwK2HchZvGZBFL4ZnxNaw==,type:str]
|
||||
fw: ENC[AES256_GCM,data:Iz9zt+M+ug6vxzjMAdGuSBSQ16+JrrXpfbsWUpoA184JEV+nC0xZi4eawLI=,iv:4lbQCgFdo5WzY5vFbn9dbkLN6iCoJNJ/5UXw74qOv7s=,tag:eCRh07yL5/D3Kzh6xgmDWg==,type:str]
|
||||
infra: ENC[AES256_GCM,data:2KEo16JyMbcySxkPUA1qvQZP5YnfKlT/lJS8FnFWSoXEL508dwiWslSDPfI=,iv:xLah1BYaNuMlSWUufhdWupzPaXbLVgVwVfXO7dKSCcY=,tag:wqkJdWNf2h5ecSBDf3T8xg==,type:str]
|
||||
auth: ENC[AES256_GCM,data:Gv73925NEyxQEXmVC3YImOfzj99ZVDH+Jt3iEl0yEN69E/1VeqH67uG5kyQ=,iv:+Dd4kY0nDZIBnB+Ft7e8GD1v9a9NjRjU/QnwnXJLJ/w=,tag:X/hOwq1fxHPPhp5VtENWbw==,type:str]
|
||||
app: ENC[AES256_GCM,data:/e7LF628qBL1+dPtfqV0myEp9MYBx4s1R6LG+HD9P/7LSsF2qG4eUl885GE=,iv:oU23xu+QTtYbT9/7Z8Q+CrCrpOJXs+Cgstvf8RASEZc=,tag:AvYzJuTKFt+dHm/uca+TGg==,type:str]
|
||||
hash:
|
||||
fw: ENC[AES256_GCM,data:cI7ZkkxkNypzTRtChxC0HVp0YxwUHXDlcs+Mm1A2OxuGekr4t2IoXnF3OieQVB8LfjH14iJDhBAQxAjww9O3dsaKy1QQx8zCZ5IabDmBfLEsdhJVGHxTBw6PJHzhlW4+1QAYnxXcWqH6Tg==,iv:s/A8I30BP4PYBf+5lBxBXySx2atYn1MYdclA1Cb/VOY=,tag:tKBs1udztZV0T3/UfAiL5A==,type:str]
|
||||
infra: ENC[AES256_GCM,data:Ifk0g0CZOIzyTeTgSVlOj5J0TsIBNQTtZYsM+MNsZ/BGhNb/NADotrBRwpgK7Lts13TQ9eNZtcm4VgWVyWVIcM2HJ+1hAKMHcgHsOlaZNZa3vbiGS/X6xvD01vFeNWC1P0A7GDsvNS0B0A==,iv:PbwSvKNl4EmLBJ/la3ePx7hzJodtLGn57XvgM3X3xtc=,tag:Qahp1EARyRqmWr2BZ/pLJw==,type:str]
|
||||
auth: ENC[AES256_GCM,data:ezk7MNsSRkF/dI8YhKB9CX+M8j876cRCkDqx64mZPaYNIWD7/tpbwqSTuTvoFsGJ9ikh3ZbNA4n3qMxMSsWstckHfcSgjUF56Bz9lCRvNqNCk/tDyj5aqxeHPXrbad4lwrgl0dPNFuPqxg==,iv:JEJnP+HnaxaLWpgsVmsLuTcxTMIA28l/ESCDnJcM1oQ=,tag:flDCxuD3L5IEfAX5BGu+YA==,type:str]
|
||||
app: ENC[AES256_GCM,data:xRr+kc1cvB2BK6DhQZQ21TvsgIgAxAJlWVMM7fbFTn9HObUIuz+a9MROGnduHKe8dp5bOkL97jlwZvk4qT8n51rYp4YvgKU/CQ7n89MqQO248hJp2MRMRWmom9Gh6HlzY4IHeMhceb/oYQ==,iv:BG4tPfwp5Qa9/H0h517fHjaE/ZIMy4vnAAQ4Fvqj2H8=,tag:meE8ZxXB8E4Pi/bS4dKMZA==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:5Xa+rIwa0hT/RCE=,iv:WwgE6FmE+hRqtAmmnnznMiCK9ApuZRm6pwILOCJNQeQ=,tag:TaVHDrAO4rV29Z2yFDdLOw==,type:comment]
|
||||
ca:
|
||||
root:
|
||||
key: ENC[AES256_GCM,data:plvrcOhFujtAJv9BHZIQwpryUmVevxI/LYAOmkp9CRyb7jxymGXFSRrUd9zWa3mT4z8lonuK9wkEkINzxG+hjFODDhnQqKpXllZ2EFNiTB/x4wEgedcsx2J/qf6TreBwXOlPCFY0GcYC4UdQFU4ZmmBmFFxe0X0T8l5Fcj27cNRvU6i6p03wXUHVHoDF4pP2NXFFqgepdkPFtvexEpSQDbnTo3unKOgwgqXXvaG9dBflU4nE4ulhiDbziqGOAFqb8Iojx0EwSYaAUG1s/QgwkLFcOSyPYoSH0VdHVlfkiyQnQC/Csbn3uj8bWLO7PhY9cz4WTd2+Z2YJELHnBEvbUFvonD61/KbXE3Zn/j9Mevoe2qizszRujyEuQD6Gw+F9mfTo7aX01XKqlj5alX+H7In3VLyKIJ1M43Y=,iv:fPv2FoE7LA/ImDQiIpwA9NFO/5MIXMcfLJxVALirFu8=,tag:I0Ya9yZ0seTpjaCbY0kxuw==,type:str]
|
||||
crt: ENC[AES256_GCM,data:t+yAyGjsbGUFfa/3wKqAHVgV15trtFrFHXRgBN5y1iJNXvqsHzdt4OO07o/d8lT2bh/UXZEHQDmx0VW+gKSouVzr+ZF2ENgXAW+d1cWWup7cLW+oC2LOf22gP3js53dGNS4+qRhPTi5M7XZztsAJgaI3+LAiDMoxoZn8jZZ2OKOB2038w8ZHCDGMUmvCMXJkk5u4o9zf8qLggdPk/MoAtQ4g4/5Q/gJsf5v6+ufZbSXnWWfwtBce7FStb3Bg06RIGG3LtDGzBxvMFpDJe3z0bidJtOlYyAJhOZF/knOTUwVlEt/Jhd9KoxRKYCMETj0eKO88bIyxZx9gmli7OuETWRyK+A8Y7xAdAoZxgeDJZjX4kcPsMy3vkGKSGRKDg+FMwX/PGwUDQmG+UyfmGqZUyc5fJWHKI8eY55jZoHR2U47tRvV3DcRlvfq8x1Ror1aMtaHfAYcTtxmhQxaWTBhpEQDMSBfMS85UMtNATQd9FXaIh3L6NB1hXCEa/3Tb03ULjkV9Ij92l041CdVUGhRbgz7iC7gy2aGap8fK4PopuqPeEsz306S1Mc1+FLrBz0Y4+545k+cNcEueKRXkColtdsTGU0JhftF3tXxynmx8W0kGKfG3o12VAN4Q8+yYPvE4XtTNVoJtzPeC+ksCem+w57gIAP+PbSdmnaEjsM/GrfTfGzJzcuCUKVDtSl8jh3B8f7f6dk0GSXftMnofdHlSXcAq3rG8oHoqCzS+k/VMz8o22uqcVHTiE0HKVK9h0jghDkkEYcGyiBsLPMlUxmkBmE8uwA==,iv:FyUTqDvjMajaHljcwnQZ9usEaL46hpvGOjNvIVUTMEA=,tag:K3h0hZfr0yjVhxpaG6bi3Q==,type:str]
|
||||
password: ENC[AES256_GCM,data:ElXnqYyR9qAiBjPqR0HVsMcknp/qqCsBbs1zLfRVqYHSX68RkNVDWOWhrIo=,iv:xiBAV2J52aQbaA9VxdUvjiYg7JTnQyeuBukTFfDCjig=,tag:lZXVek8TSTcNtcu5VyUMUQ==,type:str]
|
||||
intermediate:
|
||||
key: ENC[AES256_GCM,data:xZB2VgzLgTleX/E27lie9Cy0Ham6iGZtSfmw/wfOqH/h/HBv754uYV5XPQyenj6Mst06WiiNl/gvzCZjNAoLiKPkGWvpWZeUjeclsb3QuWjIIArarjcOaA1XX0wxsizfAZ79FU4qjY+alJlN2EnWgiyYIq/bCdhMorYi9nn3z63Q2CetzDpMILfacv4aUzIqu6iX9sgJ4cwpzlAdl0vs7Q4jUZ1eNu00zb9Lbf3NSFUuafzDNSn4FFJ5H4nFqC/okLtFjfMrWv+XPXKR/EqA77cS2gW0g8bGtpZX51cNGYlIMdXj9Coet5tgj+UG4KzJSMoTFdiXHdR1jFAvmYUcFbX1wtbGtIqK3vKcVT1UBtkxQnj8dURzuetyj21qABR6WfPXVOfgIQrTdG4bUZEw1LZbEYd8w6L57NE=,iv:nspy2dXUIGvuyTkETzMxmeEPh0u4saxc5jHfsUMC93M=,tag:v7mMF2+asasRwqIyTSlgQQ==,type:str]
|
||||
crt: ENC[AES256_GCM,data:4RrGKeUS+9oZN08WINaW61C7yGs6Atu/vA/w9GNGhC21wMWHoB3FXl6sxDkNAO+qZn0YhINXW6MF6VvmPh0Lu2nQ5wdLlhsgFat1fXrWcatqvHoD08Q6pWSVTXwN9ZLM038ucOj26Xs4C2mBCl2wddII59YzCKRcXIYoK7GWF3m3x5uWY+sP+8IZ2fQiHEaITFX1hg9tNItmWoRh7gCQ15yec6KTOuM9Ph2HI32oP1Lm4h3fW2SvIcgJqHcFObtequGFXpvZbSedesdR3v+gNVSr5oTVsEGoGwyALt/gGpK3zptTDsavARzsQPUXu3+QILyuNYHXP653g+VnSLMwEMuFdeQJaBeG4TF0Zo76dPuy8lPSawhGK1BJsEgUb++23q87nW/O5UdJsUJ7gIejrQQpH266nq8cw1Thyskypk0TrsMdrTWwOniWOLSUVf+5GZi9mLqNse89Qe9xyJlvocTdpZg7Bl9kDVFjLRO2IC8+r7NqD8PeOjxT8ojJNYXG3iDbdqyQtHtpETjLUN4ZHCo8EOdGIBAqnutV0gAxnKIcran86gtk6QIeYL62x0AgkDDEClCrQMZEOIMbhzPMml+4Y0SdcoA8DErrFiPeufDxak5gNLRJxOT/okOBi5/QK4deJ2Cbx0lSxB79d69Ol9OAKUNW855o/lcGD+Tx3bNXYzN+EaFmpku3Sv8Bvl3QloVQ4832w0bbwcqEoviuB8hDMqsmWXZS8D+cqL9uYZVObRJS8rR8QGPfPkSPy8NePWsuR1vznlyBT35eyRcKwVp+qweDIjHHgAIcSvSAVPoQ3EYT01WCpRPsiTIxh4IbLIYeqImFrb6Vn7S6tMmv3E3eCnuL/LfxiV1t3Q==,iv:bUDkP5wRWEqi9n9QEN9ETHFeWdAiEk8GUwTD4X7asRA=,tag:xYYYPlGQfhcK97tSPtM7dQ==,type:str]
|
||||
password: ENC[AES256_GCM,data:aijMXt3hTo19xVChh1gplU8sUQjmX4Y+dSjS69Kw2cEqmEJB/pelihLH96c=,iv:zP1yDLGsbL0sxJq2PF+qe3c8rNT7Knz6vKaGwMVB2xs=,tag:Oazypz0OfAYI/eptqgaINw==,type:str]
|
||||
acme_key: ENC[AES256_GCM,data:vir3SKMdU8FsZ3fBNoSMrev3vreFG4Vsex7R4hIR7Ty68x9wqsO/YpJSNkw=,iv:e7AqVbmCOkVIaje6xF8QzISU0E3JfyU4GM7/361ybdc=,tag:HC/kMa/jmVqBwCsvR31WHQ==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:EcolN4koQ/STbbgJMw==,iv:VY3FneEP+SyYh/uWXdvnDgcY79op+j7RiEgTND5+KNY=,tag:35bxqy3l6ZSf/PoQRvUubA==,type:comment]
|
||||
ssh:
|
||||
ca:
|
||||
key: ENC[AES256_GCM,data:5xMsfRvz2SmtPI+bsWpKY5u4P++DIOyuSLK4vMuTVpRu2r0X1b35rhoB3xdN65oEwH0CKvBEeZQuNdmgSbWJtkbXKxAQlli3m0myi+zXvKZiDS/bCvPLjSTi8wQ5dhILmqIagBIdWFIpf/5BmWYaWg2XHnfYZklhRlHLyKtkCY57kDdVco0fkhmc2SX28yA+5vF55dNU5ouxCg+K90dXRQaM2ZpQgZBNPy/6dF1ZWSv3oU2IvEp02tRuIZggaqiqBW6D1cxnOm/PVhvMjCtBy+EdC/+iWpGIJZqn0RkPAZ4wff90EniR3yF4p1BgQA9QkeGRdDXqoZgxWbRZl1S52Kbb2XtC9oJRle1gKJAU99bLOQVFyitW91QZ7rVTNsXJpxUk61x83QAH9qBU6CA+Sawt+fqoO3omlN5H1xOaXEqTRZgbh8GRdJKF4nGbczHR0UeYOoVrO5x8LeoE8ARYVu2ZKlRJ3nRruoBWNxxwooGsInJKqpSEoJ3MBZ0vRz/bPsABhSPB30WX4ZUovYqj,iv:mpch3JeRjhOmJU+O3KcLXq2wzRKwNQXV1pjh7HRkh4Q=,tag:y07Qj/IGHBgqLxgLmlGpWQ==,type:str]
|
||||
pub: ENC[AES256_GCM,data:rTZrT/8k4fdjm8VGCvGD4jT2DF6E41dytBVCicJEANxlYs3ByXWgQIxpLPQH2Fc3yCtJYKgERF9ugd7HMsQ1G54VgfuEOUyMyW6i/XTfU/KIa8yEFg9KhMP09hXSeA==,iv:xy1Bv45o63/oqzoB7E4U3CnbiN/Z8N8eJ6diKXdJtM8=,tag:szxdwQzusxVwWm2uq6ZjfA==,type:str]
|
||||
console:
|
||||
key: ENC[AES256_GCM,data:cnSKedN0VglTn3QwTQOIFFQM/ASROvPrYINZX7AxLbcY2UI0JSq34eN5LnOL76Fol5Gl9PUaTsg26D8dG5AlS/Egu4p/u19s14UMzNLg33r2C9eiJDO056z/oRko1gDZPIq3LWRoGkyXJFzASJ0RpVbGwoilhoCgFOS4PZjBEZO9g4pGX1OAqvhDg4/kdRJqnh6N4hAOhphP8lS8vsf/9iEQEiyEoBHepd40BsQ9NC6l1SZm2Jk32Pe1IkHZ0kJoDweY/9zdDpRdr51uTzvg1xLM9QlfiLYhZMb5R3Q3SjNV/CKpIhkZvfdNdCrsH4pF1N7UuzBmp0bfhgSeBsAUr//acs2HW+mRPoRXUyAsBeA+znX8/v3OIjr+0iBmqoIP7qhHKdSKn87JpZ7ef3QMO2gpKoYCUMurpC1eXffIB1BRxZkt+w5656CN+T1uF8tZI0WGfM2VormYmRRyAqfTWkIIseIieDV4/CZWSllICTNaWXJ6fSAscENHnAP3mXTCijVTTkNZhhVISoKvAJYsgMQChqcVUm8IXeWT,iv:nislvsSMKf/fjnmksNr3NUj0mJVeBqx+YuKkCdGar5E=,tag:IFiOxkGYC/oMqwcoMLmEXw==,type:str]
|
||||
#ENC[AES256_GCM,data:Lc10ZCXfOJjKp/f5B3ktF6VwJ3Xt5S+yOUhGjvy11/m67uVzVDriCbUIZzD48EBym+qnRytWl1jf3fDx8Eeio/GgTUyEXy2JpQnwQp0ZvT9G4w9RLWuY+ceiYx4=,iv:vIiNQ0doLXveoSbwZ1GbGNUh39coFYOGLWlOpe/RNF4=,tag:TN/9NYlwU95r6JKSCOJnWQ==,type:comment]
|
||||
pub: ENC[AES256_GCM,data:kBzNL05tQB9pqLuxHhv+YTuJG9mBkc0DUF+xoUHT4l8lvRMDxwOsw2MIcBefwFmaNLIQ6g7Cr+XomhN+muXHchSuoc2FBqoODeVxuiqz3XExviFEMSjPo4PFQN6/tumHDlCvSlI=,iv:UCdm6KOq3ycaP0PrTwYUNkyg60s67rRp/GyWlol8Ay0=,tag:Jas29pUb7fSzvtIbsdn8cA==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:N1PD5xQeHX/nrlM68FOw+6c1,iv:b9AEHsj3CnXtdczYUhY8Vsd6niDoI2b+SPNFpuKcShc=,tag:c2kXzTx3QNI/5k6PgUdPAw==,type:comment]
|
||||
wireguard:
|
||||
server:
|
||||
private_key: ENC[AES256_GCM,data:rxnsBjeYxgVJfSuthDYZAnslReXexc+/Z+/31tDFSGOhECcZBskFaYpsLKY=,iv:GFyeG07iGdixmCkL55lHpZl9/eFIE4kEcXN/avgfNgI=,tag:30IHC4wXbvk1U+aBx62pZg==,type:str]
|
||||
public_key: ENC[AES256_GCM,data:7iOIIBp3l7PwEbgBj7gF1uipExHWMwi5Bu2heT8c4G6hBa7CB+TtlvLI8m0=,iv:LrvLL9ZpZ+mUa/7FjHSuVHYpzomcne1Ac0u1oexqMnE=,tag:Ek0sYfqz85bwASVbKf0NDg==,type:str]
|
||||
console:
|
||||
private_key: ENC[AES256_GCM,data:OGC0SqqlvoVlDnkWhyCjojBBVaZEcLuNwp9JrmLH4vCkq6LQysaHeXJBp4k=,iv:Yke+FRt+vaicDfOo6WViDBoeESrHa+4L0nu6cy9FW+M=,tag:jIf2G3/tvku+Q8FZJQmaow==,type:str]
|
||||
public_key: ENC[AES256_GCM,data:Q2rPqu/vSJFLe4t4CDGy7tWT/BRAmFclSFUQ9CQYqV7UTt1ZJH5Ju4XFYkA=,iv:clrb6d9XQNgM55Ki/8guOb1H+t/GiDVJxuP/QARO5zY=,tag:FBGsAQShTVmnnIMTJEva2w==,type:str]
|
||||
preshared_key: ENC[AES256_GCM,data:ZiAROExgHCWwMyKdOY/FRgpNK/it7F3PxSD5yRr7Xhd6H18NUtujt6OSqY4=,iv:uNw8wIhafXQrzQ7o+O1PQfEBodEXYVP9Abth4COI/dY=,tag:5zn6i/8/sRv9qlFTejEQ9g==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:+kiy17Z7q3EiPgo4Ykk=,iv:vOi54XHHLNIO9U0ybpU9Cn68Ymj5W4vtQ2OhTkGAmRo=,tag:h3wdCo5UfNGlHqMpeeBf/A==,type:comment]
|
||||
kopia:
|
||||
repository: ENC[AES256_GCM,data:16V50bVVtecbF+TJcXHCx46ZPGNMgAhUOA0YbZHVTsCrOWQvTvcK2k8Iq3E=,iv:/wNbrE5GaFiQPNEp8wZ0JehbXkmah/gPm5ywNE6WVVM=,tag:vW82KTKtJ44++tqXON/SYw==,type:str]
|
||||
user:
|
||||
console: ENC[AES256_GCM,data:LZQEz7JS8CMMSlGB2/FS15VHAbko6YpCaWDZDa9tXVnmYLwFs8F39/u8kLI=,iv:WrYox/3LweqafWl96fxmezTFhKHB/2XSDSLwHljdpw0=,tag:bPwqkdeexXItkbpPQQ6klg==,type:str]
|
||||
infra: ENC[AES256_GCM,data:fwvu96Zhao5RthZptxhuv2NobY1riQzpvD4Ardc8UTwN6+HyfFVR31yTTqk=,iv:jqFEKsP2npZgeRL3E3Va7oLzbHShBO4FxLRYwnfLtys=,tag:qXescWki6oPaaSrhMsUw9g==,type:str]
|
||||
app: ENC[AES256_GCM,data:VVs8lfo8ZsbYfeKIwtaFCrpV82SguR/xxNnMZXXp8YOBP+6F2Vs5jeDtTTs=,iv:L2mS2RhiUlB9Oq4gwVs8WNF4r8vYv6zg6Fqnpe9hSoM=,tag:WYjtPdD2Lny9Kc+dWVupjw==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:gfsEXIOqhoTsiCI4uDjDeEY=,iv:SfJwBdIFY8Z4Nt2CxjuSY8PYKebQvKcg9n2xL3w7rsU=,tag:yrTNPBjrvnxydGK2X32Zlg==,type:comment]
|
||||
crowdsec:
|
||||
key: ENC[AES256_GCM,data:C7bMfJikh20PFQTe7UtP48SDUlSKKDMOul7dt9USZIVKq7LLBJV83vqbOc3xbteqPzwIYqBEndfqypSevpy/cLAPstQXL634fQGbel6trqbCApq/xjucUvnaqRKyUjk/TH3oRP9qXG8XDsgQ1o+I4b4E1alxLljMPN12wd2KIHfDGp+TURcC9DkK+NESIyQMLQg40cBaps1HcxXvg7FB1oJImM6AjqP9iybDfgkCaNAqUHxLyCHJI4rdYFflALHFkorl8jaQTazqWfuSu70x8j5tUJREksOS8arN3YIwXp4UGHQ=,iv:sbF2ZD6xS3Z3EYc6/5m3oKMghkR1q/IDzVwBX0OuTTI=,tag:NIuO8x3rP47oE/Y0EiNOvw==,type:str]
|
||||
crt: ENC[AES256_GCM,data:0Olvh8chXMx0tri9NeiWhka/bl5XRwdAQf55EwhVa2kTedETOBIjdgDqdsXhoREhannWK/1cXcxP7vpvRFMt5e06FsmPh8mSuuyRboVs9ys5p8KPYQcnlOZxfBU1J6DzE8Zq/tOf9cpdlcUVpPJ038tI7cokqhBvPGZIR2Q4/2BKWQnL8d0GvQoEfXOpNw63qQDynSvaSs/asfZf7yeYH6v3Tc4tNRBB5nl8sCq8GjTvm4xleRWax9qS0oroB/uY7S+5OCGLtJFo0A4eweOcEwWuqvpGqsOgs6s8bToeaSmPOUgsCQ2abiMtBWnyCxMxMCFNB+79lpByasf1iGRWlrhjQeUpIoWWAWU6oUbd4pMRy+j+rKV1/Cq4wF7cc7kSTh8BlFAK3Yr8DIDppiUUo53utPAl179ZkycNUzHY5Auh/jA9ZU1UZRbtIOBlIN6mVr/Y53EzigtVYlZRQ6aaQFutM8jGBnegfPhp3m+XY2WanYk1GKKj46Wh11g1YqIWVYpk5hlR1RdQoPsgZPf0yChblbdfQ14iRJqw/0pVPBvX6bKS6P2OaDHpCIBSpTE98VSEjXTkK0XU0Mu5YzyUWxIe5/BoRiF9gRFGHEDWwFWprTuFk3eUEaEZ9qoyWr0igmX73Be7y8Bre0jX1xSMjepSLV/0dSUnimhfAvT1TlhwNlxq+FGR0ZMsu8QmbYp1CqLcH93rQxoloHIs2T1+KfKAENwsjm2PshdqmOOoUkzANUmdilYCelkbXyUKXkLqFb8qnSV0jK6hG/ZVeXTzZPnODJ9Tow9bXKdxOwk16XpuMSHjCoIol2E0yD/0YKVBHAnYuz/Uz8Dl/ko//3+OaDD4TudV/nRyy4Ge4JI/kckiovMLma4dJSmADgOAXa+Ao+3N/vfUMF1F1DyRXUXsqHMygtlZZpGiswabq/MrjEvBPomzFWUmu9clWiPJ,iv:SQrBnbzApJscyGuNPE40uKsUdQCf4W73uUwanfyCGbU=,tag:KK+a0tLB+mmn4YWl5Yc0tQ==,type:str]
|
||||
bouncer:
|
||||
fw: ENC[AES256_GCM,data:wplc8z6YNuQi7bN6r27wSOmx7alVDWUBgU+pgvnH0exmRhHCHjbS9zX+4P0=,iv:fbBg0AlqOtbKgYjbiSPopJ0QwEryAEXfcc+YaUWI6xI=,tag:Ul5+MwKZyMevBIyvZH/hAQ==,type:str]
|
||||
caddy: ENC[AES256_GCM,data:fRyTH9/7OZ7oaz2n3o7DtXJCnH5l89fGSZtM3FH8sWzw8Iqj14t/qXsX5Vs=,iv:YQbozgWTmU+facWKeC+2ab2fvm47CwLbrprRiWKDRyg=,tag:Ki3hGXPJ4lWMXJYaDF0kaA==,type:str]
|
||||
machine:
|
||||
vmm: ENC[AES256_GCM,data:CF49CU6iwC8LiUMPaGMFMNGjF0n9gpSplnGkkJNk14qEkvYFTgfoUPqc964=,iv:Qi6cTieniO++EltyUkabXqsPAEb0AEmdR1ramlisthI=,tag:G85rEh6STS9pDr1zbuNUdg==,type:str]
|
||||
fw: ENC[AES256_GCM,data:uA3AfA394F8b0a2jGjU8ABHvKGNTsZM0O1woQc7gLdHte5Cn8SgfuyNgWu0=,iv:TCZ4NwJuTVPAbiWn6QWM7cRta2uXODHb/41Q1qslJsU=,tag:A7fGrietJuxyEUik3eVZLQ==,type:str]
|
||||
infra: ENC[AES256_GCM,data:rNpo77YAdoRedzJonScaT6Fhr18+T6u6/bKEzC7PYOIzEpuKh/MqzIS6Np4=,iv:D8QND39D2eqBG0USHhcc2UCxpTSuGn4SCpTCOBO0RAE=,tag:1X8IK8DNsD2m6DdtxMQTyA==,type:str]
|
||||
auth: ENC[AES256_GCM,data:neUWugEoUU+LrXijmUjd6063pvtyMuvBhiLtKR0BdAqkl126LN776x4cibs=,iv:OSu3S3AQNqk0PRR2kITKgLcniEsNhrNbpPIix3UIwDw=,tag:5OpA77ayasIQAYx7tYFD9Q==,type:str]
|
||||
app: ENC[AES256_GCM,data:mMO7DZ/oVKoNgLNGGbhIeKDfjlwxlni9c2EoULZ41WeqDEnkdp32ZPV/LS0=,iv:ex200YXZOxA+nGFnv8OxjI6hTlg0GNiIc9TIopNZujg=,tag:Bp+W7FsOgZBtKcrC6qnx5Q==,type:str]
|
||||
#ENC[AES256_GCM,data:q9DPl4EKv0g2B7cpy4YlxRk=,iv:g0tCbPnr/xqWG6MNaxjb9zSYFx2nxQPQiRRJjbsIR1w=,tag:pP47LKjzDziPwHV/0Wv0RQ==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:t/KEdBnDGbzSMAml3g==,iv:5CJufEHKR/dUsTxHyPqi8Q5Sfl6xXlY4qAviKh4YSWY=,tag:AkxRCxzLw9CjqPxNiSV1xw==,type:comment]
|
||||
ddns:
|
||||
zone_id: ENC[AES256_GCM,data:zor6X7gMJ5B3ZmCk/HMxfSuVBBBmvsnlNKbXIFhSwz4=,iv:borj6+JvYPFOx/nRIRceKBo2Spkblc4ieQ3atOSARvw=,tag:FO6ugJsz3qzLa9adj8GOUw==,type:str]
|
||||
api_key: ENC[AES256_GCM,data:JyM+sZSF2uga+B+0+gofpJ7UN922TSslKRmnm5RHHdld12rdwBpUYQ==,iv:5AHzpbaMfJIMAJnYqBaOL9k/QKGblTF0MGrGG2lTgAI=,tag:Ra16GIKDtdGTr0NXQ+VwEA==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:avhAPSvxfnseTd2OGg==,iv:yhKB6gjtztcncgm7hAnXC7PpN76dCYsJaLt85/2Zm0M=,tag:DMCROfsM3abh3U+XGvbydA==,type:comment]
|
||||
bind:
|
||||
acme_key: ENC[AES256_GCM,data:XdFARjEVV5jLrOt/Ul1eO+s4xPzsmmmlHf+hAInTic8BDJ4DvbA4u18ZqLeAOQNNEf29HkJd9Zv7yrZ1c4KYLaQc/OIZAszD4WaLVsWmRlNJLUKQFYdBo8OWXM5Ac5c6NQoWRPzZ,iv:qNrbZz4PniDaXDdxTXrKdiJsoY59iwjMw1tCL8q26A0=,tag:gyNDdXRlJhlRt5kTj2XhBw==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:FNnIRyidUh2urEgGgM85,iv:w6Z7/VLY9BtH4CNqchc/3GkWb4ez2Nb0TxdZF6RdND4=,tag:14vEc2qpBoOApdnci8ZTug==,type:comment]
|
||||
blocky:
|
||||
key: ENC[AES256_GCM,data:3hIpfdbwUzIvFhhVOl9TYoLvVLtFS0jdKSC9FGT2dSmYJP9f0qqrKEtH9+52GF3YUXvf0fkPoqAxxDf3iNh2ynAS7PMBOth3LS5mnY+NpRCZuod8PkyQOWCzkAeVla/JeAD3n3da4f8layWHY47u37XgeojQpyijCWKifEnpbjJdXVBKi440mSaFaORgDJkvSMRGcgF1o1HWz8/YricUIfv3xniQA3Ke8gg4/L9gHHFAqAZiKUBDDppHzuY5ua82FDWTgipPtoNdi+9xyeTmNdunrVAF3OrHwkNQqfLJrGOfrhU=,iv:TGbO2lfqjnsu6ZzcO5qAeQKSgE5qr2lQZi+3YuAlAGs=,tag:tE8bTnPpBXwDXYyB9YsOPA==,type:str]
|
||||
crt: ENC[AES256_GCM,data:vvT9evMqMW8isY3N0tvQCW0XFWIW98vVz0aO0o3habCbLJlB5wjF6TMA1u1xbJ9zQWX8kHTt62BxBngCHXtKFnnVN2q1hNFK/sGFpAJz/WXD/sJW8kHOAv00dwGl2/r1josB9hFmn52omxpryY2h3ZTgqLxoCpzYPoB1LvJzPKo0bS4ig+/qYbAyPe9pNbTmPzGjXutoGbOKXKAQvfZg0YNsR/nbdd0Y5eEdHL+0syH2wEZZ1ZBBNxnd9wiEmRoQHDDkDJ6VHAWfcgZcuX47jKak6LFBAOfj2lVIza78o7MSQsCT1M5DJMZu/K5mV9jJhftljnZ8MB9rX3rFcApHnFX9luLn5b7pHRwieWCNHM71gy3wHS9DFZXjYRpFqFTiXmAxtKxgL3wDIu7M3Ajrc1o1JMlsWMGVUa/InfF73NIMJMKrAPgSWXb4JgwF9HmGjbO5GiSAjRXvuFFmQBArvA7NRn6XFaRyHsig8T/5nQ4t+E0C1HjCkzMFVnUwq5C/3aEJij+cv2YaT5jVTZ5tvX/x0lykMLxd5Psy2Mqvw1++NjS1eOBmg/4q0Pero6zOl+s83fyoSCiXD+K8XHHe24M2IBITABC/Wf4L4yNrwE5S8qn7M6vbFZns1C4BpnIUqbtGeMbAx5reM30nXTWO9pI8Xl5zAPrb4gd7zdl5c6HLge3k8wdNqw2kBD/z4EDCNCPar3g4f1XMhcA1aB3FrHuLvHOkCkCmNbvZ4D4+Nams8HDQ7aNNStshLGt2Rdh8fzQ/KlQslJvgk0oLupnGuZzNWP+TO4tuR4DC/pfX9Uw3+1SDeeTFH/X4iaoSJJxqwC0D3pTvu4SUXilZ+MBE+mDEkB+PbNTuyuFkbUi9OyRFy3W175Mbr9BAdlSIAd70SpUiARqn7k3S5twV5pomxYyOaK+cuAJub/Gp8I0Y102P2rNqcASmA/Ocnogp,iv:m3r2kOi1XUVzLcKo/x9gWT22IDrnOlDYFaGxY2wd6Oo=,tag:6qOgMHBC4mrOTRJ61jhGAQ==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:xUxguG12uiQAzJGMXaaqdgTfCw==,iv:kh2nqSVtBXaAhEywAdDPbbG0p2ljX4mtjVKYXCNL20c=,tag:XGaBtxPBHSaLRYZa97+kmw==,type:comment]
|
||||
postgresql:
|
||||
key: ENC[AES256_GCM,data:XCBWU7Y/BG5kOeKqmNpqwyjePWrMzXUW2RUc+d3r8kfTMqVT2Hxe3Hh8qSCilsZOKoeEfraDKCMKBLmmaX/WGXtjnhOF87Y43i11jDPeMv4g0b3f3oh+ekckxG43pFpPUR8/IW3xB3otTdrp7Sw93xh1s6BcYVutL+opOVLwdB6JNlnx6ZAi+ppjmlHxinEa1UpnOkLC0JNIyp0i5xp5KMizNs4iNcduI3eWWZmj1z/lW1Q7dkH6rPIjtNQt0Ce8wpdsuJvPaZHHAZZ31KkSj/6n/sNhSQsgAvJNYBIsqZRG5lw=,iv:/1keHEeQzFuxaZD/Pw51IBIaBy3J/5fK7BcgF+A41Mc=,tag:Cx2AX0sPTwkmHODbuZNu3A==,type:str]
|
||||
crt: ENC[AES256_GCM,data:cnvAtbrzS3xpa+RQKhSO72xsPLAiloQZrbUL5asql6Zf2B4aNzepfZa9vlTObd4pG/nw1lIFIY4N1oh+L22j9snDXRX4BX5tANJBCiZrnqhvfDkT97xaK/86D9J6kyWmIYjlQ6bXBkvDhDII0eqigV3A/NDl8V9YApGHyAMuryWB69I4wjvVnlok2HSOgZxq0F/3Epp4hk8BuUTNvAcSeIAfpWePVHYtHRk0X3IT3KhR+Q16Ahm3fqDXFkAhs86NBaCl+kEFunGLyBqxecU8uYuU7gmofISqSDytI5ZGVt+oygHSkcQKrW/NBxY2yYs++8m5N0sLPfmtE8NFIMktpjHrUGEKnZmdUEjg7sFFRGhvpGyo77x8TPC3bD1rZJVgDwYCmKjyCO3VT9jPonV66rVOq5S8svm4pQlaT+BDPZXIqDQn4UHD7grKOdUA+zgvdBuVsUnngR/D34cPPm0Y2x4CLPmz4PBGZQu5Q4sCU+8vq/n8kNX1z2T1K/d40YBPlSunOZIZk6H5XMoy4Njftty2sIjraVy7udYEwqmUwfm9XlYqBa6QeofoxY7BaUrRjVUIcPrKLUZ13qddOoPV//gLtEDwcD37kyLw5ZbPKVdR/5rU48ENvP1UPFC47HDyhtA9/FzYweEZ1jEXSuxr6r5xJVcH5/2eyhW3Eo6ewwWeT26oVPj0zm6faeY6WVPXJX3fhMwNonAtTHzkfZCfFlDgizMtSMsMadzzTut8rlziEea9cuMS0EacIdzafoZgQsYq2ZrRhsYDbQNGAE/DzK3Hkrtp8eqJDNyRyCIsn1+B0A0ci8hADSHPS3q4tQD2JPb5zj6/0PNt0oIIBRcYuXgJW1nathtP718i3Hhi+cmqvZtza7XKUkxNYNYLO9hGnVTNY+mHD8HW94QdAQ8ikfF8tSBv0N4/ebyVIkaS9Nes8MyOQJbzfGhmmpeuo8jineQsf6w=,iv:6gXqS7C8lypzUvjExURswSwnUXG1bTC2+BxUkK0D36w=,tag:cd6URiL6TxM8GxyYirvYDw==,type:str]
|
||||
#ENC[AES256_GCM,data:Zu3CNVkCUlW6BKGh/rhTTqrGv/7H2BG7,iv:vW4cAVvla/Ya0S89DTvo9k3do9517F+AHMLb36Ey19A=,tag:neDpBA97R77p88Im92xn8w==,type:comment]
|
||||
password:
|
||||
postgres: ENC[AES256_GCM,data:XlpsKT0/3VgNesMdifvHlYZ2dh7mlMEnxi0MJpQZiQ+1tZ0/3zMxQ7+vwec=,iv:akcPRmDZQfFLxelG7V87UnNB8ez28PPLCmY1MYfzStU=,tag:14jvIKP7Htfh+/oMwLYC2Q==,type:str]
|
||||
alloy: ENC[AES256_GCM,data:ifgJH2e7MTAJ/+ppdWHEmLC3DAsKHWNi8j4w1ZVjUh4tN1cDLDJR3EvJTl0=,iv:rDYUkVe6idIf5Si5E9V+mvBaIdYQTJJCB2rOV0Suvr0=,tag:xDCL25NwuTp6H1DOGTIm4w==,type:str]
|
||||
ldap: ENC[AES256_GCM,data:mJrxIhXynHxJhncw3upHpOkXIw+Ka9bmDBJwkDjYl+D9Pg4RDvL6WzBjthw=,iv:y8MUYo6VhgTzbWh/+n7/hf1Jw+L2KcdxKvulPJ67xn8=,tag:4ZFpj1UdOwXmaZjYvC/s3A==,type:str]
|
||||
grafana: ENC[AES256_GCM,data:P9okJ7bcsqmeGstkSwbDq/RgnG+lFrgAOvcj8A5lOTpmHaSlXGiKG+ybXa0=,iv:Di1ghnxIbAb/u7uo/mJCC3QYVjdweTHaQDZmXTx8OG4=,tag:DT3a1zgU9sTr0BXpyoZ/SQ==,type:str]
|
||||
authelia: ENC[AES256_GCM,data:OqyloAADO6KKEaBjGLsJc9GTe77wn6IvA1VCD2dfCWxx+zgzUYh87fK1XX8=,iv:QIOHNTdNnzcY/f3Co8dPdNHykhBnYRhm43nt35hbALM=,tag:DLQq58GrZd+Ul7MSn6s9uQ==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:VuOcF5INAvCNDvXhcAc=,iv:zdTFTKaII606RjjDJbdUyv8jGba8abL7lJNTsPH5C74=,tag:cYSefZHKIuvHmAzoxierQg==,type:comment]
|
||||
ldap:
|
||||
key: ENC[AES256_GCM,data:OCje8b2x62vVQDV2DXvy28UxY9IIMtRoSLyXVFwNe+sRWA5prW67Vp0XcwwL00nP6hagkXGNRxy0eXx0VYXiktQBeQQe7TC5bUpzJlDCyGmi9BsbDhzShSoSM0v/TxX4UYZ16PbdVxyEIxlD5J/SpbQdg/VvVA6oJgLU4SfZCYmKRZ/gC3I4cKGzFJAT7NLAnC74/Wngz2nE6ipzXiQaDHnSuitLHF/RGoAgE5XyelyXag5wGaB8EAUgmuM8woI5g7RES9885bPOdt/Q1MUNNmEz7jIBH4AVGo8stxRioYmAcZ0=,iv:6Fi0DyvzmrQN+OVclRFZZyXCW8v1nfizj0saGkV7qTY=,tag:AkMtsUaRIgxNKZG1oYPTTg==,type:str]
|
||||
crt: ENC[AES256_GCM,data:1SJlTokgS71mW3rEQG1fTLs1cp1Mraww58stg87Bf2PryFsKw88va4HB+bsKzkCRgykQoj8iDSqM7tc7Wze1HWz+bgFTgIqluRQpZtbcmfYVlqefdIUcJPAntqe/eEaA8Hj3ozTNMlKFspv13vPwjSJHGrHcektwlcEI58+S3lhu/IrIfdxryBm97E2UQczznRE3zuP3MiBYUV0oj9Bcm8KWDKqa3DLwudp5wwyw/OG6DGg48isEvNxaMJhuEkiMwMNR+zZXgAvYcYteMaW0p1UXNFHzxMpOWshU1zYL6U9vZkKfpVMoMoTPW3+SO+vxlJVafevStEipUFd48XmOo31uMQH9zWh/hbLM8j/fiTaW+kY89XwkQ9ZUOx8+YXgcfBb04FAbtLEXMbC/eF0meVdjAHv0TEBPF1a/F4m9Kqv1GkJ4RA8jHKFng7vWsRGl7WhmxrCxjrJrYu9ptP7iMvbaaqMWG1YOSwwZUe2HvrM7WTlJxeRukwvW3rOglAUdFODJhsWbATpobuu716fKLqDcprKa+vA5l7VMghqLf7tWRGXmT3O3RgTGDwqjokx0q0+4ib10cgzrRCkwuTBDiLYRdxd2eZFWumLOlKKQyVAMJ9YZmUnH2VNULazcN7Tznpqm3vdA8pC6Em7ELTxYTUvkaye27jRVyilkZvoX8oLiWyEpMpPAajoVntmPnGTF5ppChQ0EmyuFXlv0tsU3K+bxmM5VYVNy4S+1cMOvEwGDuSGJ9nZfS0BFm8NXDp+BbEIAa/DVc6yOjVEwi1Wh0khxbplkW9feWfkLqrdlxF2khNOTePIyEDMzs5/CRq+kzLy0U+7BeyX28jleRpeAQL6nlOZ6Ha3AyQUhxC1/KVOK/kgAlGVi0gyaxZy0yuF4whFKN7+oXB+CrJoCyX3mjrOVqQIOeNIK6tLac3hW/cATu43uDQ==,iv:BmdsX6o02n/ekhnTQrpTUgM3lqXCyQNYtMbexI1Ziho=,tag:7AI4lOFSXDxR7n1zoqcE1g==,type:str]
|
||||
seed_key: ENC[AES256_GCM,data:q6kodsHzwDuf0UHPSk9VbEI9pCwePJWcA7o6dQiZqyM=,iv:EbozH0UpLThEXjmWkNhkpHQxabH/K3/lJ8xki3lLGZo=,tag:rKO8csevxpH5kzzFWQoang==,type:str]
|
||||
jwt_secret: ENC[AES256_GCM,data:AfPcqKAwdsHfiYHrZ6yKqOxD93gBcLEvZ4N3M8nhWMQ=,iv:awfSXZbc7Tzg8sRqUkp71TXivLb663ZjaxNkskE1Heg=,tag:e541/ejk7x+GOhJeoUPMGA==,type:str]
|
||||
#ENC[AES256_GCM,data:/5Po+8hjJg74ZBepaNWTzZy7JrTjiwo2DNFT76hZTUFKEdchNd4sfdy3tbVwL5y9QPC/kC3kvBZL2oA0+WzcUmd51Ht4/xS6CnUCpodBrSWNHu4H+ohdmz/jMplREeJVWAFHuTZROqB9v3hw3rYJ5Gb+5XROAuzT4pKfrPoJ1B+ysGUpuvybhrC1O5Tg6IPs5fvIiR3yExGcIFuywZBiiA==,iv:gupWDnXb2TD1N8GhHwpiYuz0sDciLX8V0ww9cFKtFNI=,tag:7eDx5RZOrNXOUshvdijV5w==,type:comment]
|
||||
#ENC[AES256_GCM,data:+Q0n+z/P2NwlY6/aOzMNe2yZaoN7uSctcH8DlTUR6dYgNTnZlGQNNFAHs416XVMcYHyBqPwkSvdQLGl5TcJReZLm+8ESeYeQhjWgHZWKnGJK0e46cdMhznXKjQ==,iv:dayGt24JAY3+LV3OS0JUxM7vxfOUAoTl7O33d6y4wVI=,tag:KcfHxeqjmyAUfNDELBfx/w==,type:comment]
|
||||
#ENC[AES256_GCM,data:6AE31A6F6mflPwwac4jVxY5kJPYaKlYzNjtUC9/VmCPeS8iuvoFmxHNQ9cwxLa20Nw==,iv:N7tQ9RyBYvSCKzbLGWgH8NgyKCJpNM5cupGK9e9pQbM=,tag:nAduK50DDywtkkQ03psKRA==,type:comment]
|
||||
#ENC[AES256_GCM,data:o4Uc0IfSKbSCHAh00aHkN1g/+FoK/Ffm26iT//ZGc9WTncusMdZslfX9AQWXXOtRwOP9hjpw7KZA5FWsYEGzyIJNcvq0nayEgwBmCB1RmmDVcvVT2jEjKLGCIqYMHT10ZUdFuls+SSKtE6Kk6GMrrV/MEGzn7rKIHSlflv3+Iav8p2cblRoEFqAxrbNgbvcMzSDpWH9XCInhD0Sw5ABViNvBc6CVb0ZfZEuyoBF4EhQ=,iv:bs9iS3fmJtb0K5fc/DXKYWho9+1GBWmN8jOBEhGr8Bw=,tag:Ry77miT/7UKA2pLE3kMcag==,type:comment]
|
||||
password:
|
||||
user: ENC[AES256_GCM,data:DT9h51o6z70A4QeoKvCbUo98JFxILgB5tkHeX60CZuCl0GHTa//mRpIUEvo=,iv:Pa9iqXeKDHHBz524zeRImYEkXmY50s7Z+Z4KYt3sNT4=,tag:UTS5VIqbRA66UVDrDXwuPQ==,type:str]
|
||||
authelia: ENC[AES256_GCM,data:G8ZGsLKqEmMzQ5NMAgirF5BQraHNqixtI6dyyaeNhTdXebjJZML52xL36p4=,iv:ZtHAsFYmrQxr+qoQLPW/eme0+nsT148KRsXmW/LNLlU=,tag:Pvjs/eylkgxJpmGBsRmjcw==,type:str]
|
||||
grafana: ENC[AES256_GCM,data:vWmU3ZKcolETWAY74C3OMD8gMXDeYk+DqssACL0xefIPi5IkbrhYWmnWAnA=,iv:wcRms3Zp8kPM4USRPVa0UHpCTK36SWhK9C8yHSWu2Cs=,tag:gU5S/6fdMZVd/ih3Yd5uJA==,type:str]
|
||||
il: ENC[AES256_GCM,data:/CyMeo1+rIUAYiB25nI0,iv:jsyiiRN5z9GqcUnTZ0CZo4s+umTc2zeY2FPp+tVOC9o=,tag:cwOHcqMysCxX57w3a+Pzpg==,type:str]
|
||||
morsalin: null
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:NronfCPkbPQLilb38VmliNn0Yg==,iv:AbC7xk46CJ5dqU55IbyPX+OZVEROz+OGnJfxoZmaKwE=,tag:GEsziOOFhDF16Vjqx59SNw==,type:comment]
|
||||
prometheus:
|
||||
key: ENC[AES256_GCM,data:MNmUv4J5qVRB2NH3vFcIPGsx8ZB7ggYLK/4HyI2hBE+KhBGgh/9GeIauN6VDxO0xPqVe6xsY41vMDE8K5wmQyvTOi2fyXzL6LDxPHKVZVUKMjRgiYKJJh9hghzVeQwKwTjfZ+eXFgSKf+ENpSgh4+zbFqm0eVhhZy6EQ38494IlwS/UsojC831xg0OeeHNF5QrE7rIG8zo+rjsntpWZbJzSM9BgzFAAfW38Ywi03lstbJi8IEq/gFmZjQxU3CFHicD0X/jKY/uBxZB8lu8Km2ZevGDLFGwGX3zpcYxou3667m9M=,iv:1Px2X4RKD1sbQ9NhFW9rf0Q8cu0ex8P2RjmR5wUmFbA=,tag:rKkYDav55LfUwUueaA9Qfg==,type:str]
|
||||
crt: ENC[AES256_GCM,data:0eNafjanGCWtqCiavj5vAQKi9nczPShx0w9dfULmP03sPZTh74FCZwZvu2vQ8i0GbKNZdHMKYAP/Utyd1XdttaVr4Kvf6ggkQXj5a0AOakRmTOjkO2WhZtWUVd/fJSfcsifa1gG+x5O32yVZXx4pWSVtcV57g+BnksTyt5JBnPz+u5pEBK0VZKRSjIjlvanLM+l/Dp1tyrmKarFX+28bCDUxB3I6wZUEnF35wUNbu6pVMcR8JofQG6KrmsjixMWPRDz+u1w8b/+nTGOXyykUUjxH7a6wEf7/RTGNBwT44CrSACxybJMCed2MBjY42jA0Lm4ISwE8epvOkpptu7NRyEgMiVke5mNSH9ZGaUe6mCBpbUVkL+tUQG5rwclsL6ijaCyqsWSD5bb2i6wGhmPe5/ERKxmLjOWNeAQSf1HiJc/bSXOSpt15DuGgwwJ4jfebOqdshUy7CMc7KclQj7ppqhTYhRHbM1mJwCJr6QGVDh5xSzFDSH1qbCRdeXkPEkm7WxRJbAtzY73UmO4eqhsp5n6+PtiFNNqQg66mOGF8N7PlEKh2vcoxgtjnTTVHVlgiAHuT2TMWNuhO3qwJeF6G3zApFSPuJWcEH7PGAeezL+qUF2TzHVthOHQMUNFr1m8i4ms/hCE9DGSv5oo+X7YKO6xcIe00xNQEzMNk+HqmAKed9pl/eBHhD62UvQNZh66e1VjWpOE/ig0hP6vgKSwyQL6xUtJWWzYl184KcWokw+O9Vyw2FCR++0iu+Zn+PIYYQg4Vwpqd5VM0cj0tIB7W1+aLz8hGIOgQKDjQUshWeMxEjESILgb3+7lNyZkKT/y48ocHL/dedHRLXuxUcSQ6ZUGhWf33so7763Gimo2hK3jmIaprnx4LGyiBKPPxkSl+Bt7seUiFJ041olDmO+fUDvi0ko166CA+3mUxeoeNRh74J2RPHR8dmy1okp1NLEQztyHw4Ps=,iv:14bMOT+Fn8j2kFDQxTuwtsTyYnp4fIF0WRpQntz4afE=,tag:fWnktLbiQzG8UExa3nspUA==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:8Pk3De3AWQPtW+o18w==,iv:O05B1JyftUqN/0/pCi5HReEOltp5jJ6GRER5+NXkoMY=,tag:Tl4duRnv+EoZ4xWVwMfEWA==,type:comment]
|
||||
loki:
|
||||
key: ENC[AES256_GCM,data:gtQ3j59WJd3YxreCMoR70VZBJubaR8UfoeAEYgZR8KGIYkEGPnBCMEmBlu/L4qZO0fHg0DLSN/ixLbmvbOluTMNF1rbj/5W4F0O79YI2RztXZ3oxrtYf4dRPxIoCuOQi9PtD5VrduBUGGhvDW9yae9QxzQ+Ca7KwMHgOLu/5+VW6YdQRBdgEQycSDsdMvRTmFwnQuSxuQhWxhu9GqR2WGx3cinQIZ8ewr147aOiZNgUjnHLfYjtzRXqQtK0HEvjNVKBWPuOWLYRa+h10TQlKMQMZn7x7QJlDZhsF/aRqVRNwYc0=,iv:0vVdSLKOgFTwvUbW1uU2vINYwnXMIYIzOl+2BqsJ7Vk=,tag:nm34OwNXseUTzO/KUmT2Vg==,type:str]
|
||||
crt: ENC[AES256_GCM,data:O1if/oi5wJQNhHftNEwRhSvdnloaiE8EIJ0dlY9DO2Lml1rz5+2LfwGnN/mHGFOkIZri2AhizPUqXios5kKYgdh7ib4jD2C4DC8crKO9XiNiiChzqE0WqP/sda9UJL9zzmmm3WtkGljcL1iyr4zuCvH0uuIMX6W+NohIu19JT9wqamwMHBCEYuQ6gFAVOBnsz5Rsa6v2LBsIsUBadAzngUcrIztT1UO0cHiplBq5s+TkC96wWrlAUiaV1Lcf1aABDrI6o2u4uv6Vwv/d4AQrEpaNvH1N3un/M3lOIek53atwMYw598/BAioJfZXRTQ4qeqcv9+WxFJSpG6XrWxx941St6N3ITJcAMVmKQFfupj257oyazHF4oqyJKsgXQBTXlMdLPDLH/HTRVfv5k1qD5RQ6AXJrMy4NQrE4BlLBPkLU1wxyg2REqd6eKMgw1PQdqTeZHZrQCGzxWeY+rv/0v5jwSFzC/YY+hOZRz3BRpfufWC9mZQZpNoH8yccVhPybVT22YMMVljLUEg/0BICm9Q4mSMpc9hEJ7VwHZo5pT4DuNiVjComTpcnnrEgK3yYGBB6jsAAkU+zNmOZ6AkCvKAma2DVbOhwUx1ZuBruc4GsfJcHGWqWogr4zBpgDg9FOtLF28yQpfKDWZEdx1eq1Bu9gFhK1FoBxrzd7mX5ADn0XeRbFDn/G+C24ShA+D+rmhARAdCtz6M4uk5IZ3w+L8NA/qWyZ+bgaXX8KrpDOV+/7KFStD4FXkVk20+IaMpb6OSYskqPq1ICI0MIFsONajO8gCd026B6WD/hLsGvkLL/58IwtAd+bRBceXHgoqXeTjyqNgKhhiqmKejZUphzrIsMx+GWdP70GOdcj41I5PSN0GbMnXQTRPGJo/GYN4pP3TbtmVrEvs5rMuGe0WiDiXQGM2hAreGMnt43Ge7DjyB+BPAx6ZA==,iv:1E1u18aWSRZFKewRnH+pJKN9xCpFUcJ0Dy4kq4yMprY=,tag:nmI9X0IrT545vUWhoIdhHg==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:yHgd8KBDPYeMjKzUOimdOA==,iv:ozyRymtPEII2luBads2GHyLf4Vdhf4EXNaF82SNmQm4=,tag:1mOJAmR5kVRBjm0SbQkqlw==,type:comment]
|
||||
grafana:
|
||||
user:
|
||||
id: ENC[AES256_GCM,data:32LNqOb8pzi0/18=,iv:YJrYaQRE+veDhaEUefGWLbNJo1toHGmEOpqrNV3IDfg=,tag:ENryvH9ec3EbDhBB2bdHug==,type:str]
|
||||
password: ENC[AES256_GCM,data:MFw7TAvzpL0EW2o+w6hF5qrLYVkn0HsQOXqBk9AQq7GxK4uAEDCi/YL3goI=,iv:HSpJL2CZKXHQYhOJLy6HzWARootl8Y1yMGhaMT0XRfM=,tag:t0VHDYHCZJwDcR1VcRFdCw==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:k+Y8/BDL9G+C1EnnJjy7gz4=,iv:IU/ZlXVvtX+zaeU7Zcz5baYk8ceDz95dZgzpl5/L9lg=,tag:t0OzLQCM+Up0wLkc3B/R/Q==,type:comment]
|
||||
authelia:
|
||||
jwt_secret: ENC[AES256_GCM,data:NOsbV8poM41bodRZeNJ6vnRYIl7vGKXm2BpBNeXWVeE=,iv:1G4PnaoopJMIt7D+8x0x3ui5tefMPRnSI5KJRv4IuTo=,tag:EkEHgeJ3ta4htrgOCnYldg==,type:str]
|
||||
session_secret: ENC[AES256_GCM,data:tPudIXLrAKMhR3VPFj8U1g/+FRvYgBo0wXLNf/a72x0=,iv:atfRSZNUYEYFK92+0WOvsD5Gi4tMEKv+dwsFcRDrEtM=,tag:cJu5G4EYQ9EnYOQ4w1OSpA==,type:str]
|
||||
storage_secret: ENC[AES256_GCM,data:g3Z8t/2xFZJMz4baIfY7pGoAOdoKsr+Xn4POBl1lQCk=,iv:i9Owc4w76qC1rFSUXLv4NuW6/Y2rmgSoTr/EnZuRVE0=,tag:zitZ/UAgXiUSuyWDhvHa9A==,type:str]
|
||||
hmac_secret: ENC[AES256_GCM,data:c6Xn0QceaQWIFDCFr6UAQcr9M/Np2aGCkcNiXJfM79vFakT5L8q27+38Mvs=,iv:QSpnN/ZVYNogHfFq10E1rR8jXnI/qLs3Z7k2qKHFt4A=,tag:N6Wx52yCmGx2kJlyQXl7bQ==,type:str]
|
||||
jwk_rs256: ENC[AES256_GCM,data:e0rbiDCUadbuRL3dFZ//LMMYimQ3THJtZo1OqkKntwayh10DbvdNrEhs6HF0VAMtVh5nkAaL69V3tqZnwLUadSg0Oomum8v9GkTE527iupAMjWRrXzAR/nsjvjI8gPUL3NJk++v0VA6ew/Gb9WfGlhUlmkf3K72Ab+gGiD8+xfAFeqRE/k7vHkTxkNwD1hRFnE+XhkUa4Q021nSd7xrW80sHwBWTKKUqA08xuouQN8Gkbjj22NgicT5rhy4VJiV8OnLCERLWc8F6LmDM9vLrTiPBvsGn1eX09fvVRtw40Wo0VSgklm9+REQtjefBhXuVxVDR3DXNzPliLNL3MOrvlcweDU8uxFVuml23FBBkJypJLJwbWvxwFQk1OWjiQ9jPel9+9gYu1xHg/dKeEsDf8GyMVJz60BDEQH5YnEwI1R6rPnJLZnmZVhRtoxmKRE8/oE3lP30tvOVKwRL/f3rXCyB1PYDR/2NsWtj61inzgn1BuMDl/tHDKjGhsCu2+ECThD756p6cjQnGftSSoGlwhmMCqA8I+6WUjMPqEsqietWKbMCRk000ufLp57wU4i7BvUVPSpiVO58lf6n/zs6hHBYDWNfoxEa2gha4csmCTkhCrzf+N+UJQmoMDOIQe/gSqPNcwcW/+q8K8zr2b4cMIyLbwZIyiez0RvPRnM/KuM9UmFAKfW1xdtyxalNLMOBjpqeZFnCIPFRQy6COP/dZNA9xUQX4TXXsL+qTk0vlU41/gcORgw9HQFRkLiRtrnqvRUMXipIDU6SIRipbBJ1GawH5nPTdHdbjdr7Wh0s2RUjIzLNvT0Lz0VRii2dlVRdURbtFl8R8frijuE9LG9xKY2Z4f/ojo71h6HcJvrvMOGm4iE8V5+cdthlwn4Hpyl8nLinJWLyVjhc4bzmIlo+VZvbq9o/keSfCb3wrI39L3Wy/bpoKzXx/U3eTVIIXRDrBpK+4fmYeSEi2JRJjAHHvs8De7c0wKLq9qOctIFvELwueisDIkyNGYykX1+JXa4YbuTYaOSLJNbk9B6UE17Vbr6FD9N/8n5JveXzfd2dTROQBbWmHyKa0qR7MC9foPdyUVImj1Z06w91OwRyAi+/GBiUE8ivKD9AmnTjrvX1uZhp9qGSzP9f3RkCd6lFDQ0YhSCVHQAYOrDsdBX50zqqmZEPPevIXXPnaJpSgIaOCamBLIHqrxX9KOFM3ApicE2BhXX4xN2QWFl8HGu2cVD1e9bINKrpLGqR+rQQE822OQqMqw3kZsi7lo46YPOrpXLsetxPJlLftQ7bdaCPONZk3M18xvxESYclDeGk7LJ8Lp5CjtBterF3Ka/0r7cY4OxWusTypOY3jmVDILZTMlVOKoYiJgjIHxwXFdoqbtGMeGi83CY2/SfoHn7BSrU2669O3liX0L7hzGOLerkiVozbmC3TPq+JxGNw7dA79mXCqRDQEeqAjeha6J3wmvTvdmkuPIbO7ryFtDg9VwbULfgl07WzkES5nVyQDeamKv76ERRF/EIjQGgiWRY5MDyXAhVnzy9ATEbOnBTXeks6863CTKa/3lhhtDUGeo+9tTXcEUqLPkq1jh9xYo80OUp99J1483n5iE7EEBfB13McRwsJPufViyMWIQX9KDmRZmbCjhe/Jrj6joapQcY1Fw5MaZJgfIIfzz83GnekgTG9sz7Vfq2p4qiPDONLhY6qL9ENl8Cm/tWq/Xjvk+v/gaT65L9uvGLtkYKv7OpbPtTzieGHtYmddLZNr34Ly06PHxajLL+X6LeB5wmeC7jvanLh9vW6VqwNRn6kstS9reM4kHRhYTNKlDB9pOOz/cK0p0wcNzVvqetoYtZAX9TgPcYumhZQUPsXYsuC2Gdo88seihGKND9jtepvu2OwKRT3raSpsG+rum86Q95ulRsE/rhg4BvBXs8U62E16gL1KamtRkPcjXT/2aO1t0gh6JiBbQAYemnOaJCanycbnQcZal5oSvqPLAxzFpcjTkPNVFhYyiGe0ekcaYkCs9PYuM3hqP+qNAwjQmK7bfpK+eZNGT1gwikmlUtokTvRvQjmFynfbQ5oUoOHQuxuqWOa8KLi2NwMMmaJ4LXuzozUY8KD2EXmlmrxteCZBtQNfa7BxulUMlPRHG5bqKsBc9l380I1XU+aR2qmqHxdrd9698sIXxVK5zM1vhwI0fb6V61u86iYIAdSoitzhRQu8lK8prJXxcZWOQWehV03wvDnqkU4F2Qm/XYCXJgTx8PJyGKP2w90K7TtkW1YMWrBXmnwr,iv:av1JOLQd7WoZr4O8e9PU8nEZlaf+Bs7LLbGZs/4hm88=,tag:sZ8zyjRmhyYRdwntXTOfPg==,type:str]
|
||||
jwk_rs256_public: ENC[AES256_GCM,data:2IP+w7X5ZfYUH+upr7qtjno45RXXUT71hG9Xs/VMY9aWOv6KGLpK17OEo7hVUaXwmOWOzAQl0V79bGZjIowabAoba15+IEi38L973i6F44kM9pb4N29Z2LjmLoZ/blNpl82C0ZIO/+OQ+OCRxVV8b9eZ+E1ckpvEk24NmOV2o9H2E1EU6QBOQGmYt39mnD/tQKNtE0/Q0+HbW2bz9dWqTScjH6CcwBwhtn3dhU/kbXjLc27XG6pxMKInKLo6GZmjLA3PDRQY9O2cYnFN1nDRKdOqHpbEnAPU4DiUSronJZGq6R6Z+3JGkWXH2OUTXaP8itLpXYBioY8BKH02QA+YVxnzxC0cBooNW9BxFb/GQdeLqFawNZ2lH9+743svXIRjjKp3jyn1Bn0TnDxgirZSfmvBdrgOy1fKl0qpMBYrBVLaAP1+T4MxNNa1kQqnmt9wke7aYrjVroi3/33TE9oU/xW6SW6Y+3lLEB6kJIGYb/m+qhwksOrqXRDom8G5hocUqMX3Q1fkiv8Jt/qvmuz8oSFNsjVF/4AZFESacfAF9pyerPUemyti6Y+rVjeY1yUv3+BHGgu8OiF7lqlIUm5O7NGhNQ==,iv:41P+xnnSOQK4H1dm5EohB5FmXsuaKXfSOFr+ROgoTWw=,tag:7a0+DsaDDK1DlkggQQd6vQ==,type:str]
|
||||
jwk_es256: ENC[AES256_GCM,data:Q/ZXBPopDOD/sook4a50CYUMCcjNuPfHHqxWekRrCtLzFL7EaXdko6HFbL4vI5IRNOw/uzN0tuxQNZHR3ln+cVL5OnT8x+IiOVXoz8k6fKJVIWSWReiaQxHWmLSHILHodPH2dWOPj7+ffrK8wmRGcyCAS4QfXSFwChTl43wA3H+aI9yhGAaWV1YzTbb87r16724sJGTPIR59ZJhuAJlz+LYF54fnc2J5oyaFBTGtoSRdYAnCkO4fUOWPqWpIKR1ETY40xOMyjOMpvKP8Nv6ZTwYOubPxLmpclFO/hj4R9SDowsH2ZP4PRViU1RmE2gbRnQ==,iv:5BNxP8ALgoo58lvlIdO/cwTKu0xI50wK4xo0uYU3kZc=,tag:Tc1CtmV2NSmDwKjl8NgO5w==,type:str]
|
||||
jwk_es256_public: ENC[AES256_GCM,data:utXk4AXeVQuNkImDWNQvA0JAEZAOyA4RMxix7xI2x3g0D4W3dyoTDD18LqLW5v6aA9cZmvcPtl0iSvrkxOrNJiDGJLHBNSa11q2HVAyJq7FTIRZkJOJz7WP+V7qjfmpiPw/PCS4GSWE8U5dvPcocxlPq13jmeCupz01ZRky8SIHdPiBN9a6EGMCxgTRhWUisIkV4i+1JTyb6jAR45ul6KFttxLZr7VPdu0M+pNRlJGSRPA==,iv:S448BFJqSfdnD7NcfMsq/Rb7w88IV1JhvrGlBrKW9zQ=,tag:yVDSLkUa2rMLZc5KpDC+2A==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:T4Wtn49AAxPd2QUFTR+q,iv:bH5goGWBDqumAat9dUv2OwfCUJUpuVqncTMqMBZUXhI=,tag:G+W6hHA+yftQ+4RJpXrxHg==,type:comment]
|
||||
switch:
|
||||
password: ENC[AES256_GCM,data:qu0f9L7A0eFq/UCpaRs=,iv:W8LLOp3MSfd/+EfNEZNf91K8GgI5eUfVPoWTRES2C0Y=,tag:Q5FlAOfwqwJwPvd7k6i+0g==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:UfrFHblh4F20kzKZ,iv:+gouH3z5BXLnALq1Fcs0H6SQ8Gnz6noeeRhltWSgzJQ=,tag:JXqIQjRZGtnx4y+/83CFFA==,type:comment]
|
||||
dsm:
|
||||
key: ENC[AES256_GCM,data:jxQRPNuioZbznadJa7sdhbntABsi+nc6Y5TJsyMXwKRvVUbQw8p3snp75d9WVmOfq4uj8wBGen0noa/6xtWo4ZiHsIg1Svh/5xAN37zueB6NmK/z+BW2y8HaIkNhjcinusnT2SWE2ahguizMNM90FpXgmTt9Zv7wVwRkifDLWpH+rs5zmyMWPtpT2RN3+k7tVh8XWVevek/DxG4h+jtoYhTVzndMC5oe/A60MHBJCj6kaksGlX3vIDbRo5A0FEKX8uWI6k6U2osFc4SHIvpljYmPagj3EwPaTc3mbl8IJsXFVH4=,iv:7O5oQa1fELjIt6f3nQ+fWDFirAexgioS36/Nozh656o=,tag:t1RHmY8QC6mE9PVPJg426Q==,type:str]
|
||||
crt: ENC[AES256_GCM,data:N32+8CItiwbW8drpnL65weS35SY8uP8vcw9wBDFOxGFQjs6EyEwsMUVh1ndMpmDSUKWz7c7ji0HisC710RqnZw9l2NMg6R57DeXR/WsLW4LiAT7sFuDBcqorTB+6Nk0K9wLLdnsKpUQgl8oV9ffnWXZdfI5skKCDMNB40WJAYY/3wx9iT3wDQWaunq/1NT0SZHrtXXTj1JYiLbfDaTwTvkuqqUv1cXvOjonL2Cp4aNT/zjwK6c/TRbKdhIs/7tnUUE/lJx74eARfrMQy/3y6h2xK9pgruASuJxMw9Tyaj6Ya0FMNMIezO3GPQbFCE/IRfmCE6vX2RXUjVqX8wd/d4m4KNuMsN3hbwC3vQ6r+DcYdaTUfGIu96xfKSiSax/ZPQ4JhTyqthkGgpE0Ob67aVELrZkyhc/kvvSxafVSvP63C/nHPQnXMgitdRddYFq7487Vbq03frxiyID1WkqeUavc+Tn3dyA8c7aqVvbW6vZCAwUzbKD0nwPuBUtKZQpJKxHvtx2390PW7a214zkPLcw5LH3FnNacopiNfs6dNEeW/UsGysYkoBRXfrAPMX4UL53TvUTrpuCBhthJ4rgqjhgTfq9GtomP7piuf/tnMAO33qSHPM3w2ocLWeLyOiqYESFmXoBAsiu33LVzuVryFVw75pgrGAsc2wwKhcu4JC0cNgUE44ENIIjffVQX/mcvPvHxuI05vtzM0N8kOFPwG7iAVrO1eUEpwUjZwUwkk8QRsuIhZ6W7aYx7TLdPDpjmy6XCYGNHZgHg6jU7v18KkPep1YarAnsVYFzHQwfZIMOzW7DHlHq38NJW8lWq7zkg+kY6JDVy0nttlAUSskWNeCHdI5Xy3Rz3t7V6t1+UxkSy3roQCZOYjiaknwrXSctsgqucKaJCq4w0Tty36kaIXwOQYVm9JqDIztOmer4fW8Es7OEbLwA==,iv:26fGb288JEbtA0UcAmiYcN+UunrUOw2S6fKjGMetgwE=,tag:GmUJb9LJ186HNOF4AhfmLg==,type:str]
|
||||
il:
|
||||
password: ENC[AES256_GCM,data:6LiNif7aIGgGBBdVYpl4K8L8ev6EPru5x6HvX2yJ0oiDQb6G9AI+ZsaKamc=,iv:Y+eijt1PmNZR9c9uCzBnzJT9BDc3w/P4VzsbvrPRU64=,tag:2KKRtTSYzrJKy9VX/2J5eQ==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:IXJNy9PmMPn9uowSMMrNPYqaW5PZ13JTeu1t7eNlapxmnV3EAl3I3xbMK5A=,iv:UcG2E6zgoKkPfUiHr0A+gvnApCkBJG2GROfacwD634Q=,tag:nSFn9yaCadJGlGy/aCvc2A==,type:str]
|
||||
hash: ENC[AES256_GCM,data:Y2/FNYbID0trRS5UpP2MX6UcLWxlRoXu9VLeU9DU9whEwNLbf4gYrxI7Q7etQe6HidBuoIJNxKajf3t0fI0ptbXnJaxzMh/v/CsiDg2p568o3KIyfB1PruGRKUrTuJneREUHg5jRXMYCwcRUQ4C5WgAyjd2spGlTQO0OLEqh0wkTtvs=,iv:YTYoaBy3QwlSrmx/K5woiXAHrh0RkawF+uQ4rQuP7WU=,tag:Ej6ZjTFvKjw6BrXbd0lf0g==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
sops:
|
||||
age:
|
||||
- recipient: age120wuwcmsm845ztsvsz46pswj5je53uc2n35vadklrfqudu6cxuusxetk7y
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0TVVta2V6UHB4V3NmV0tR
|
||||
V0hmbUw1bUpSSk4zQXZ4MHlaVzdJU0VSWm1VCnZaMUg1cjJyOEFyOWxPNm9lWkVm
|
||||
QlRBK1kyQ2JnQ1ZZdlF6b3UvVEtrTFEKLS0tIFpVelk3MDg4QXBJSWwzRlIzSTIx
|
||||
UmliaFNxVTBqRkI1QWJpWGpTRWxETW8KEY/8AfU73UOzCGhny1cNnd5dCNv7bHXt
|
||||
k+uyWPPi+enFkVaceSwMFrA66uaWWrwAj11sXEB7yzvGFPrnAGezjQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-03-14T19:40:47Z"
|
||||
mac: ENC[AES256_GCM,data:EUVSxs6FPhKMSSmHe8P/d0IyBZsNb3q7AYj06j98bklAMYYVOludVePdh45MSvn92lDn712Muy6pqcJzDpsPWyxgXngywTu2SGV1yRCyA7U7RloRxlNROuDiugMkJWOtHcKArytVChUHT2PnzagAJR2kBSApbjUsC/xUTMBpsNM=,iv:SsJW2fMNEJHT2M+gjW5TKu6AYoxsf9jKf5T9KgJoF40=,tag:ItVweaSxts2Cm1VKkLp0/w==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.12.1
|
||||
@@ -0,0 +1,67 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=Authelia
|
||||
|
||||
After=caddy.service
|
||||
Wants=caddy.service
|
||||
|
||||
[Container]
|
||||
|
||||
Image=docker.io/authelia/authelia:{{ version['containers']['authelia'] }}
|
||||
|
||||
ContainerName=authelia
|
||||
HostName=authelia
|
||||
|
||||
# Web UI
|
||||
PublishPort=9091:9091/tcp
|
||||
|
||||
|
||||
Volume=%h/containers/authelia/config:/config:rw
|
||||
Volume=%h/containers/authelia/certs:/etc/ssl/authelia:ro
|
||||
|
||||
# Default
|
||||
Environment="TZ=Asia/Seoul"
|
||||
# Enable Go template engine
|
||||
# !CAUTION!
|
||||
{% raw %}# If this environment were enabled, you would have to use {{/* ... /*}} for {{ go_filter }} options. Go engine always processes its own grammar first.
|
||||
{% endraw %}
|
||||
Environment="X_AUTHELIA_CONFIG_FILTERS=template"
|
||||
# Encryption
|
||||
## JWT
|
||||
Environment="AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET_FILE=/run/secrets/AUTHELIA_JWT_SECRET"
|
||||
Secret=AUTHELIA_JWT_SECRET,target=/run/secrets/AUTHELIA_JWT_SECRET
|
||||
## Session
|
||||
Environment="AUTHELIA_SESSION_SECRET_FILE=/run/secrets/AUTHELIA_SESSION_SECRET"
|
||||
Secret=AUTHELIA_SESSION_SECRET,target=/run/secrets/AUTHELIA_SESSION_SECRET
|
||||
## Storage
|
||||
Environment="AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE=/run/secrets/AUTHELIA_STORAGE_SECRET"
|
||||
Secret=AUTHELIA_STORAGE_SECRET,target=/run/secrets/AUTHELIA_STORAGE_SECRET
|
||||
# OIDC (HMAC, JWKS), This part needs the clients to integrate with Authelia in order for it to activate.
|
||||
Environment="AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE=/run/secrets/AUTHELIA_HMAC_SECRET"
|
||||
Secret=AUTHELIA_HMAC_SECRET,target=/run/secrets/AUTHELIA_HMAC_SECRET
|
||||
Secret=AUTHELIA_JWKS_RS256,target=/run/secrets/AUTHELIA_JWKS_RS256
|
||||
Secret=AUTHELIA_JWKS_ES256,target=/run/secrets/AUTHELIA_JWKS_ES256
|
||||
# LDAP
|
||||
Environment="AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE=/run/secrets/AUTHELIA_LDAP_PASSWORD"
|
||||
Secret=AUTHELIA_LDAP_PASSWORD,target=/run/secrets/AUTHELIA_LDAP_PASSWORD
|
||||
# Database
|
||||
Environment="AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE=/run/secrets/POSTGRES_AUTHELIA_PASSWORD"
|
||||
Secret=POSTGRES_AUTHELIA_PASSWORD,target=/run/secrets/POSTGRES_AUTHELIA_PASSWORD
|
||||
|
||||
Exec=--config /config/authelia.yaml
|
||||
|
||||
[Service]
|
||||
# Wait for dependency
|
||||
# They run as rootless podman container, so their port is not opened until they are normaly running
|
||||
# Check their ports with nc command
|
||||
ExecStartPre=/usr/bin/nc -zv {{ infra_uri['postgresql']['domain'] }} {{ infra_uri['postgresql']['ports']['tcp'] }}
|
||||
ExecStartPre=/usr/bin/nc -zv {{ infra_uri['ldap']['domain'] }} {{ infra_uri['ldap']['ports']['ldaps'] }}
|
||||
ExecStartPre=sleep 5
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
# https://github.com/lldap/lldap/blob/main/example_configs/authelia.md
|
||||
# authelia.yaml
|
||||
# certificates setting
|
||||
certificates_directory: '/etc/ssl/authelia/'
|
||||
|
||||
# them setting - light, dark, grey, auto.
|
||||
theme: 'auto'
|
||||
|
||||
# Server configuration
|
||||
server:
|
||||
# TLS will be applied on caddy
|
||||
address: 'tcp://:9091/'
|
||||
|
||||
# Log configuration
|
||||
log:
|
||||
level: 'info'
|
||||
#file_path: 'path/of/log/file' - without this option, using stdout
|
||||
|
||||
# TOTP configuration
|
||||
totp:
|
||||
# issure option is for 2FA app. It works as identifier. "My homelab' or 'ilnmors.internal', 'Authelia - ilnmors'
|
||||
issuer: 'ilnmors.internal'
|
||||
|
||||
# Identity validation confituration
|
||||
identity_validation:
|
||||
reset_password:
|
||||
jwt_secret: '' # $AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET_FILE option is designated in container file
|
||||
|
||||
# Authentication backend provider configuration
|
||||
authentication_backend:
|
||||
ldap:
|
||||
# ldaps uses 636 -> NAT automatically change port 636 in output packet -> 2636 which lldap server uses.
|
||||
address: 'ldaps://ldap.ilnmors.internal'
|
||||
implementation: 'lldap'
|
||||
# tls configruation, it uses certificates_directory's /etc/ssl/authelia/ilnmors_root_ca.crt
|
||||
tls:
|
||||
server_name: 'ldap.ilnmors.internal'
|
||||
skip_verify: false
|
||||
# LLDAP base DN
|
||||
base_dn: 'dc=ilnmors,dc=internal'
|
||||
additional_users_dn: 'ou=people'
|
||||
additional_groups_dn: 'ou=groups'
|
||||
# LLDAP filters
|
||||
users_filter: '(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))'
|
||||
groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
|
||||
# LLDAP bind account configuration
|
||||
user: 'uid=authelia,ou=people,dc=ilnmors,dc=internal'
|
||||
password: '' # $AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE option is designated in container file
|
||||
|
||||
# Access control configuration
|
||||
access_control:
|
||||
default_policy: 'deny'
|
||||
rules:
|
||||
# authelia portal
|
||||
- domain: 'authelia.ilnmors.internal'
|
||||
policy: 'bypass'
|
||||
- domain: 'authelia.ilnmors.com'
|
||||
policy: 'bypass'
|
||||
- domain: 'test.ilnmors.com'
|
||||
policy: 'one_factor'
|
||||
subject:
|
||||
- 'group:admins'
|
||||
# Session provider configuration
|
||||
session:
|
||||
secret: '' # $AUTHELIA_SESSION_SECRET_FILE is designated in container file
|
||||
expiration: '24 hours' # Session maintains for 24 hours
|
||||
inactivity: '24 hours' # Session maintains for 24 hours without actions
|
||||
cookies:
|
||||
- name: 'authelia_public_session'
|
||||
domain: 'ilnmors.com'
|
||||
authelia_url: 'https://authelia.ilnmors.com'
|
||||
same_site: 'lax'
|
||||
|
||||
# This authelia doesn't use Redis.
|
||||
|
||||
# Storage provider configuration
|
||||
storage:
|
||||
encryption_key: '' # $AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE is designated in container file
|
||||
postgres:
|
||||
address: 'tcp://{{ infra_uri['postgresql']['domain'] }}:{{ infra_uri['postgresql']['ports']['tcp'] }}'
|
||||
database: 'authelia_db'
|
||||
username: 'authelia'
|
||||
password: '' # $AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE is designated in container file
|
||||
tls:
|
||||
server_name: '{{ infra_uri['postgresql']['domain'] }}'
|
||||
skip_verify: false
|
||||
|
||||
# Notification provider
|
||||
notifier:
|
||||
filesystem:
|
||||
filename: '/config/notification.txt'
|
||||
|
||||
# This part needs the clients to integrate with Authelia in order for it to activate.
|
||||
identity_providers:
|
||||
oidc:
|
||||
hmac_secret: '' # $AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE
|
||||
jwks:{% raw %}
|
||||
- algorithm: 'RS256'
|
||||
use: 'sig'
|
||||
key: {{ secret "/run/secrets/AUTHELIA_JWKS_RS256" | mindent 10 "|" | msquote }}
|
||||
- algorithm: 'ES256'
|
||||
use: 'sig'
|
||||
key: {{ secret "/run/secrets/AUTHELIA_JWKS_ES256" | mindent 10 "|" | msquote }}{% endraw %}
|
||||
clients:
|
||||
# https://www.authelia.com/integration/openid-connect/clients/synology-dsm/
|
||||
- client_id: 'dsm'
|
||||
client_name: 'dsm'
|
||||
# It depends on application
|
||||
# hash vaule generate:
|
||||
# podman exec -it authelia sh
|
||||
# authelia crypto hash generate pbkdf2 --password 'password'
|
||||
client_secret: '{{ hostvars['console']['dsm']['oidc']['hash'] }}'
|
||||
# If there were not client secret, public should be `true` [true | false]
|
||||
public: false
|
||||
authorization_policy: 'one_factor'
|
||||
require_pkce: false
|
||||
pkce_challenge_method: ''
|
||||
redirect_uris:
|
||||
- 'https://{{ infra_uri['nas']['domain'] }}:{{ infra_uri['nas']['ports']['https'] }}'
|
||||
scopes:
|
||||
- 'openid'
|
||||
- 'profile'
|
||||
- 'groups'
|
||||
- 'email'
|
||||
response_types:
|
||||
- 'code'
|
||||
grant_types:
|
||||
- 'authorization_code'
|
||||
access_token_signed_response_alg: 'none'
|
||||
userinfo_signed_response_alg: 'none'
|
||||
# [ client_secret_post | client_secret_basic ]
|
||||
token_endpoint_auth_method: 'client_secret_post'
|
||||
@@ -0,0 +1,17 @@
|
||||
FROM docker.io/library/caddy:{{ version['containers']['caddy'] }}-builder-alpine AS builder
|
||||
|
||||
RUN xcaddy build \
|
||||
{% if node['name'] == 'auth' %}
|
||||
--with github.com/caddy-dns/rfc2136 \
|
||||
--with github.com/hslatman/caddy-crowdsec-bouncer/crowdsec \
|
||||
--with github.com/hslatman/caddy-crowdsec-bouncer/http
|
||||
{% else %}
|
||||
--with github.com/caddy-dns/rfc2136
|
||||
{% endif %}
|
||||
|
||||
FROM docker.io/library/caddy:{{ version['containers']['caddy'] }}
|
||||
|
||||
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
|
||||
COPY ./ilnmors_root_ca.crt /usr/local/share/ca-certificates/ilnmors_root_ca.crt
|
||||
|
||||
RUN update-ca-certificates
|
||||
@@ -0,0 +1,49 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=Caddy
|
||||
|
||||
{% if node['name'] == "infra" %}
|
||||
After=ca.service
|
||||
Requires=ca.service
|
||||
{% else %}
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
{% endif %}
|
||||
|
||||
|
||||
[Container]
|
||||
Image=ilnmors.internal/{{ node['name'] }}/caddy:{{ version['containers']['caddy'] }}
|
||||
|
||||
ContainerName=caddy_{{ node['name'] }}
|
||||
HostName=caddy_{{ node['name'] }}
|
||||
{% if node['name'] == 'infra' %}
|
||||
AddHost={{ infra_uri['ca']['domain'] }}:host-gateway
|
||||
AddHost={{ infra_uri['prometheus']['domain'] }}:host-gateway
|
||||
AddHost={{ infra_uri['loki']['domain'] }}:host-gateway
|
||||
{% endif %}
|
||||
|
||||
PublishPort=2080:80/tcp
|
||||
PublishPort=2443:443/tcp
|
||||
|
||||
Volume=%h/containers/caddy/etc:/etc/caddy:ro
|
||||
Volume=%h/containers/caddy/data:/data:rw
|
||||
{% if node['name'] == 'auth' %}
|
||||
Volume=/var/log/caddy:/log:rw
|
||||
{% endif %}
|
||||
|
||||
Environment="TZ=Asia/Seoul"
|
||||
|
||||
Secret=CADDY_ACME_KEY,target=/run/secrets/CADDY_ACME_KEY
|
||||
{% if node['name'] == 'auth' %}
|
||||
Secret=CADDY_CROWDSEC_KEY,target=/run/secrets/CADDY_CROWDSEC_KEY
|
||||
{% endif %}
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
# CrowdSec LAPI connection
|
||||
crowdsec {
|
||||
api_url https://{{ infra_uri['crowdsec']['domain'] }}:{{ infra_uri['crowdsec']['ports']['https'] }}
|
||||
api_key "{file./run/secrets/CADDY_CROWDSEC_KEY}"
|
||||
}
|
||||
}
|
||||
|
||||
# Snippets
|
||||
# CrowdSec log for parser
|
||||
(crowdsec_log) {
|
||||
log {
|
||||
output file /log/access.log {
|
||||
mode 0644
|
||||
roll_size 100MiB
|
||||
roll_keep 1
|
||||
}
|
||||
format json
|
||||
}
|
||||
}
|
||||
# Private TLS ACME with DNS-01-challenge
|
||||
(private_tls) {
|
||||
tls {
|
||||
issuer acme {
|
||||
dir https://{{ infra_uri['ca']['domain'] }}:{{ infra_uri['ca']['ports']['https'] }}/acme/acme@ilnmors.internal/directory
|
||||
dns rfc2136 {
|
||||
server {{ infra_uri['bind']['domain'] }}:{{ infra_uri['bind']['ports']['dns'] }}
|
||||
key_name acme-key
|
||||
key_alg hmac-sha256
|
||||
key "{file./run/secrets/CADDY_ACME_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Public domain
|
||||
authelia.ilnmors.com {
|
||||
import crowdsec_log
|
||||
route {
|
||||
crowdsec
|
||||
reverse_proxy host.containers.internal:9091
|
||||
}
|
||||
}
|
||||
test.ilnmors.com {
|
||||
import crowdsec_log
|
||||
route {
|
||||
crowdsec
|
||||
forward_auth host.containers.internal:9091 {
|
||||
# Authelia Forward Auth endpoint URI
|
||||
uri /api/authz/forward-auth
|
||||
copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
|
||||
}
|
||||
root * /usr/share/caddy
|
||||
file_server
|
||||
}
|
||||
}
|
||||
|
||||
# Internal domain
|
||||
auth.ilnmors.internal {
|
||||
import private_tls
|
||||
metrics
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
# Private TLS ACME with DNS-01-challenge
|
||||
(private_tls) {
|
||||
tls {
|
||||
issuer acme {
|
||||
dir https://{{ infra_uri['ca']['domain'] }}:{{ infra_uri['ca']['ports']['https'] }}/acme/acme@ilnmors.internal/directory
|
||||
dns rfc2136 {
|
||||
server {{ infra_uri['bind']['domain'] }}:{{ infra_uri['bind']['ports']['dns'] }}
|
||||
key_name acme-key
|
||||
key_alg hmac-sha256
|
||||
key "{file./run/secrets/CADDY_ACME_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
infra.ilnmors.internal {
|
||||
import private_tls
|
||||
metrics
|
||||
}
|
||||
|
||||
{{ infra_uri['ldap']['domain'] }} {
|
||||
import private_tls
|
||||
route {
|
||||
reverse_proxy host.containers.internal:{{ infra_uri['ldap']['ports']['http'] }}
|
||||
}
|
||||
}
|
||||
|
||||
{{ infra_uri['prometheus']['domain'] }} {
|
||||
import private_tls
|
||||
route {
|
||||
reverse_proxy https://{{ infra_uri['prometheus']['domain'] }}:{{ infra_uri['prometheus']['ports']['https'] }}
|
||||
}
|
||||
}
|
||||
|
||||
grafana.ilnmors.internal {
|
||||
import private_tls
|
||||
route {
|
||||
reverse_proxy host.containers.internal:3000
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=CA
|
||||
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/smallstep/step-ca:{{ version['containers']['step'] }}
|
||||
|
||||
ContainerName=ca
|
||||
HostName=ca
|
||||
|
||||
PublishPort=9000:9000/tcp
|
||||
|
||||
Volume=%h/containers/ca/certs:/home/step/certs:ro
|
||||
Volume=%h/containers/ca/secrets:/home/step/secrets:ro
|
||||
Volume=%h/containers/ca/config:/home/step/config:rw
|
||||
Volume=%h/containers/ca/db:/home/step/db:rw
|
||||
Volume=%h/containers/ca/templates:/home/step/templates:rw
|
||||
|
||||
Environment="TZ=Asia/Seoul"
|
||||
Environment="PWDPATH=/run/secrets/STEP_CA_PASSWORD"
|
||||
|
||||
Secret=STEP_CA_PASSWORD,target=/run/secrets/STEP_CA_PASSWORD
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"root": "/home/step/certs/ilnmors_root_ca.crt",
|
||||
"federatedRoots": null,
|
||||
"crt": "/home/step/certs/ilnmors_intermediate_ca.crt",
|
||||
"key": "/home/step/secrets/ilnmors_intermediate_ca.key",
|
||||
"address": ":9000",
|
||||
"insecureAddress": "",
|
||||
"dnsNames": [
|
||||
"{{ infra_uri['ca']['domain'] }}"
|
||||
],
|
||||
"logger": {
|
||||
"format": "text"
|
||||
},
|
||||
"db": {
|
||||
"type": "badgerv2",
|
||||
"dataSource": "/home/step/db",
|
||||
"badgerFileLoadingMode": ""
|
||||
},
|
||||
"authority": {
|
||||
"policy": {
|
||||
"x509": {
|
||||
"allow": {
|
||||
"dns": [
|
||||
"ilnmors.internal",
|
||||
"*.ilnmors.internal"
|
||||
]
|
||||
},
|
||||
"allowWildcardNames": true
|
||||
}
|
||||
},
|
||||
"provisioners": [
|
||||
{
|
||||
"type": "ACME",
|
||||
"name": "acme@ilnmors.internal",
|
||||
"claims": {
|
||||
"defaultTLSCertDuration": "2160h0m0s",
|
||||
"enableSSHCA": true,
|
||||
"disableRenewal": false,
|
||||
"allowRenewalAfterExpiry": false,
|
||||
"disableSmallstepExtensions": false
|
||||
},
|
||||
"options": {
|
||||
"x509": {},
|
||||
"ssh": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"template": {},
|
||||
"backdate": "1m0s"
|
||||
},
|
||||
"tls": {
|
||||
"cipherSuites": [
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
||||
],
|
||||
"minVersion": 1.2,
|
||||
"maxVersion": 1.3,
|
||||
"renegotiation": false
|
||||
},
|
||||
"commonName": "ilnmors Online CA"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ca-url": "https://{{ infra_uri['ca']['domain'] }}:{{ infra_uri['ca']['ports']['https'] }}",
|
||||
"ca-config": "/home/step/config/ca.json",
|
||||
"fingerprint": "215c851d2d0d2dbf90fc3507425207c29696ffd587c640c94a68dddb1d84d8e8",
|
||||
"root": "/home/step/certs/ilnmors_root_ca.crt"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"subject": {{ toJson .Subject }},
|
||||
"keyUsage": ["certSign", "crlSign"],
|
||||
"basicConstraints": {
|
||||
"isCA": true,
|
||||
"maxPathLen": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# https://github.com/grafana/grafana/blob/main/conf/defaults.ini
|
||||
[paths]
|
||||
data = /var/lib/grafana
|
||||
logs = /var/log/grafana
|
||||
plugins = /var/lib/grafana/plugins
|
||||
provisioning = /etc/grafana/provisioning
|
||||
|
||||
[server]
|
||||
protocol = http
|
||||
http_port = 3000
|
||||
domain = grafana.ilnmors.internal
|
||||
root_url = http://grafana.ilnmors.internal/
|
||||
router_logging = false
|
||||
|
||||
[database]
|
||||
type = postgres
|
||||
host = {{ infra_uri['postgresql']['domain'] }}:{{ infra_uri['postgresql']['ports']['tcp'] }}
|
||||
name = grafana_db
|
||||
user = grafana
|
||||
password = $__file{/run/secrets/GF_DB_PASSWORD}
|
||||
ssl_mode = verify-full
|
||||
ca_cert_path = /etc/ssl/grafana/ilnmors_root_ca.crt
|
||||
|
||||
[auth.ldap]
|
||||
enabled = true
|
||||
config_file = /etc/grafana/ldap.toml
|
||||
allow_sign_up = true
|
||||
|
||||
[auth]
|
||||
disable_login_form = false
|
||||
allow_anonymous_device_id_auth = false
|
||||
|
||||
[security]
|
||||
# local admin
|
||||
admin_user = local_admin
|
||||
# local password
|
||||
admin_password = $__file{/run/secrets/GF_ADMIN_PASSWORD}
|
||||
cookie_secure = true
|
||||
cookie_samesite = lax
|
||||
allow_embedding = false
|
||||
|
||||
# [smtp]
|
||||
# enabled = true
|
||||
# host = localhost:25
|
||||
# from_address = alert@ilnmors.internal
|
||||
# from_name = Grafana-Infra
|
||||
|
||||
[analytics]
|
||||
reporting_enabled = false
|
||||
check_for_updates = false
|
||||
|
||||
[log]
|
||||
mode = console
|
||||
level = info
|
||||
@@ -0,0 +1,47 @@
|
||||
# https://github.com/lldap/lldap/blob/main/example_configs/grafana_ldap_config.toml
|
||||
[[servers]]
|
||||
host = "{{ infra_uri['ldap']['domain'] }}"
|
||||
port = {{ infra_uri['ldap']['ports']['ldaps'] }}
|
||||
# Activate STARTTLS or LDAPS
|
||||
use_ssl = true
|
||||
# true = STARTTLS, false = LDAPS
|
||||
start_tls = false
|
||||
tls_ciphers = []
|
||||
min_tls_version = ""
|
||||
ssl_skip_verify = false
|
||||
root_ca_cert = "/etc/ssl/grafana/ilnmors_root_ca.crt"
|
||||
# mTLS option, it is not needed
|
||||
# client_cert = "/path/to/client.crt"
|
||||
# client_key = "/path/to/client.key"
|
||||
|
||||
bind_dn = "uid=grafana,ou=people,dc=ilnmors,dc=internal"
|
||||
bind_password = "$__file{/run/secrets/LDAP_BIND_PASSWORD}"
|
||||
|
||||
search_filter = "(|(uid=%s)(mail=%s))"
|
||||
search_base_dns = ["dc=ilnmors,dc=internal"]
|
||||
|
||||
[servers.attributes]
|
||||
member_of = "memberOf"
|
||||
email = "mail"
|
||||
name = "displayName"
|
||||
surname = "sn"
|
||||
username = "uid"
|
||||
|
||||
group_search_filter = "(&(objectClass=groupOfUniqueNames)(uniqueMember=%s))"
|
||||
group_search_base_dns = ["ou=groups,dc=ilnmors,dc=internal"]
|
||||
group_search_filter_user_attribute = "uid"
|
||||
|
||||
[[servers.group_mappings]]
|
||||
group_dn = "cn=lldap_admin,ou=groups,dc=ilnmors,dc=internal"
|
||||
org_role = "Admin"
|
||||
grafana_admin = true
|
||||
|
||||
[[servers.group_mappings]]
|
||||
group_dn = "cn=admins,ou=groups,dc=ilnmors,dc=internal"
|
||||
org_role = "Editor"
|
||||
grafana_admin = false
|
||||
|
||||
[[servers.group_mappings]]
|
||||
group_dn = "cn=users,ou=groups,dc=ilnmors,dc=internal"
|
||||
org_role = "Viewer"
|
||||
grafana_admin = false
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# https://github.com/grafana/grafana/blob/main/conf/provisioning/datasources/sample.yaml
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
url: https://prometheus.ilnmors.internal:9090
|
||||
access: proxy
|
||||
isDefault: true
|
||||
jsonData:
|
||||
tlsAuth: false
|
||||
tlsAuthWithCACert: true
|
||||
httpMethod: POST
|
||||
secureJsonData:
|
||||
tlsCACert: "$__file{/etc/ssl/grafana/ilnmors_root_ca.crt}"
|
||||
|
||||
- name: Loki
|
||||
type: loki
|
||||
url: https://loki.ilnmors.internal:3100
|
||||
access: proxy
|
||||
jsonData:
|
||||
tlsAuth: false
|
||||
tlsAuthWithCACert: true
|
||||
# Tenent value set "to solve no org id"
|
||||
httpHeaderName1: "X-Scope-OrgID"
|
||||
maxLines: 1000
|
||||
secureJsonData:
|
||||
tlsCACert: "$__file{/etc/ssl/grafana/ilnmors_root_ca.crt}"
|
||||
httpHeaderValue1: "ilnmors.internal"
|
||||
@@ -0,0 +1,43 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=Grafana
|
||||
|
||||
After=postgresql.service ldap.service
|
||||
Requires=postgresql.service ldap.service
|
||||
|
||||
[Container]
|
||||
Image=docker.io/grafana/grafana:{{ version['containers']['grafana'] }}
|
||||
|
||||
ContainerName=grafana
|
||||
HostName=grafana
|
||||
|
||||
AddHost={{ infra_uri['postgresql']['domain'] }}:host-gateway
|
||||
AddHost={{ infra_uri['ldap']['domain'] }}:host-gateway
|
||||
AddHost={{ infra_uri['prometheus']['domain'] }}:host-gateway
|
||||
AddHost={{ infra_uri['loki']['domain'] }}:host-gateway
|
||||
|
||||
PublishPort=3000:3000/tcp
|
||||
|
||||
Volume=%h/containers/grafana/data:/var/lib/grafana:rw
|
||||
Volume=%h/containers/grafana/etc:/etc/grafana:ro
|
||||
Volume=%h/containers/grafana/ssl:/etc/ssl/grafana:ro
|
||||
|
||||
Environment="TZ=Asia/Seoul"
|
||||
Environment="GF_PATHS_CONFIG=/etc/grafana/grafana.ini"
|
||||
# plugin
|
||||
# Environment="GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource"
|
||||
Environment="GF_FEATURE_TOGGLES_EXPAND_ENV_VARS=true"
|
||||
|
||||
Secret=GF_DB_PASSWORD,target=/run/secrets/GF_DB_PASSWORD
|
||||
Secret=LDAP_BIND_PASSWORD,target=/run/secrets/LDAP_BIND_PASSWORD
|
||||
Secret=GF_ADMIN_PASSWORD,target=/run/secrets/GF_ADMIN_PASSWORD
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,64 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=LDAP
|
||||
|
||||
After=postgresql.service
|
||||
Requires=postgresql.service
|
||||
|
||||
[Container]
|
||||
Image=docker.io/lldap/lldap:{{ version['containers']['ldap'] }}
|
||||
|
||||
ContainerName=ldap
|
||||
HostName=ldap
|
||||
# They are at the same host (for Pasta, it is needed)
|
||||
AddHost={{ infra_uri['postgresql']['domain'] }}:host-gateway
|
||||
# For LDAPS - 636 > 6360 nftables
|
||||
PublishPort=6360:6360/tcp
|
||||
# Web UI
|
||||
PublishPort=17170:17170/tcp
|
||||
|
||||
|
||||
Volume=%h/containers/ldap/data:/data:rw
|
||||
Volume=%h/containers/ldap/ssl:/etc/ssl/ldap:ro
|
||||
|
||||
# Default
|
||||
Environment="TZ=Asia/Seoul"
|
||||
|
||||
# Domain
|
||||
Environment="LLDAP_LDAP_BASE_DN=dc=ilnmors,dc=internal"
|
||||
|
||||
# LDAPS
|
||||
Environment="LLDAP_LDAPS_OPTIONS__ENABLED=true"
|
||||
Environment="LLDAP_LDAPS_OPTIONS__CERT_FILE=/etc/ssl/ldap/ldap.crt"
|
||||
Environment="LLDAP_LDAPS_OPTIONS__KEY_FILE=/etc/ssl/ldap/ldap.key"
|
||||
# Secret files' Path
|
||||
Environment="LLDAP_KEY_SEED_FILE=/run/secrets/LLDAP_KEY_SEED"
|
||||
Environment="LLDAP_JWT_SECRET_FILE=/run/secrets/LLDAP_JWT_SECRET"
|
||||
|
||||
# SMTP options > you can set all of these at the /data/config.toml instead of Environment
|
||||
# Only `LLDAP_SMTP_OPTIONS__PASSWORD` will be injected by secret
|
||||
# LLDAP_SMTP_OPTIONS__ENABLE_PASSWORD_RESET=true
|
||||
# LLDAP_SMTP_OPTIONS__SERVER=smtp.example.com
|
||||
# LLDAP_SMTP_OPTIONS__PORT=465
|
||||
# LLDAP_SMTP_OPTIONS__SMTP_ENCRYPTION=TLS
|
||||
# LLDAP_SMTP_OPTIONS__USER=no-reply@example.com
|
||||
# LLDAP_SMTP_OPTIONS__PASSWORD=PasswordGoesHere
|
||||
# LLDAP_SMTP_OPTIONS__FROM=no-reply <no-reply@example.com>
|
||||
# LLDAP_SMTP_OPTIONS__TO=admin <admin@example.com>
|
||||
|
||||
# Database
|
||||
Secret=LLDAP_DATABASE_URL,type=env
|
||||
|
||||
# Secrets
|
||||
Secret=LLDAP_KEY_SEED,target="/run/secrets/LLDAP_KEY_SEED"
|
||||
Secret=LLDAP_JWT_SECRET,target="/run/secrets/LLDAP_JWT_SECRET"
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
server:
|
||||
http_listen_address: "::"
|
||||
http_listen_port: 3100
|
||||
http_tls_config:
|
||||
cert_file: /etc/ssl/loki/loki.crt
|
||||
key_file: /etc/ssl/loki/loki.key
|
||||
|
||||
#memberlist:
|
||||
# join_members: ["localhost"]
|
||||
# bind_addr: ['::']
|
||||
# bind_port: 7946
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: "2023-01-01"
|
||||
store: tsdb
|
||||
object_store: filesystem
|
||||
schema: v13
|
||||
index:
|
||||
prefix: index_
|
||||
period: 24h
|
||||
|
||||
limits_config:
|
||||
retention_period: 30d
|
||||
reject_old_samples: true
|
||||
reject_old_samples_max_age: 168h
|
||||
|
||||
common:
|
||||
instance_addr: localhost
|
||||
path_prefix: /loki
|
||||
replication_factor: 1
|
||||
storage:
|
||||
filesystem:
|
||||
chunks_directory: /loki/chunks
|
||||
rules_directory: /loki/rules
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
|
||||
compactor:
|
||||
working_directory: /loki/compactor
|
||||
delete_request_store: filesystem
|
||||
compaction_interval: 10m
|
||||
retention_enabled: true
|
||||
retention_delete_delay: 2h
|
||||
@@ -0,0 +1,32 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=Loki
|
||||
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/grafana/loki:{{ version['containers']['loki'] }}
|
||||
|
||||
ContainerName=loki
|
||||
HostName=loki
|
||||
|
||||
PublishPort=3100:3100/tcp
|
||||
|
||||
Volume=%h/containers/loki/data:/loki:rw
|
||||
Volume=%h/containers/loki/etc:/etc/loki:ro
|
||||
Volume=%h/containers/loki/ssl:/etc/ssl/loki:ro
|
||||
|
||||
Environment="TZ=Asia/Seoul"
|
||||
|
||||
Exec=--config.file=/etc/loki/loki.yaml
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,12 @@
|
||||
ARG PG_VER={{ version['containers']['postgresql'] }}
|
||||
|
||||
FROM docker.io/library/postgres:${PG_VER}
|
||||
|
||||
ARG VECTORCHORD_VER={{ version['containers']['vectorchord'] }}
|
||||
|
||||
RUN apt update && \
|
||||
apt install -y wget postgresql-${PG_MAJOR}-pgvector && \
|
||||
wget -nv -O /tmp/vchord.deb https://github.com/tensorchord/VectorChord/releases/download/${VECTORCHORD_VER}/postgresql-${PG_MAJOR}-vchord_${VECTORCHORD_VER}-1_amd64.deb && \
|
||||
apt install -y /tmp/vchord.deb && \
|
||||
apt purge -y wget && apt autoremove -y && \
|
||||
rm -rf /tmp/vchord.deb /var/lib/apt/lists/*
|
||||
@@ -0,0 +1,28 @@
|
||||
# @authcomment@
|
||||
# TYPE DATABASE USER ADDRESS METHOD
|
||||
# Local host `trust`
|
||||
local all all trust
|
||||
|
||||
# Local monitoring connection (host - infra VM) `trust`
|
||||
hostssl postgres alloy {{ hostvars['fw']['network4']['infra']['server'] }}/32 trust
|
||||
hostssl postgres alloy {{ hostvars['fw']['network6']['infra']['server'] }}/128 trust
|
||||
hostssl postgres alloy {{ hostvars['fw']['network4']['subnet']['lla'] }} trust
|
||||
hostssl postgres alloy {{ hostvars['fw']['network6']['subnet']['lla'] }} trust
|
||||
|
||||
# Local connection (in postgresql container) needs password (127.0.0.1 - container loopback)
|
||||
host all all 127.0.0.1/32 scram-sha-256
|
||||
host all all ::1/128 scram-sha-256
|
||||
|
||||
# Local connection (host - infra VM) needs password (169.254.1.0/24 - link_local subnet for containers in pasta mode)
|
||||
hostssl all all {{ hostvars['fw']['network4']['infra']['server'] }}/32 scram-sha-256
|
||||
hostssl all all {{ hostvars['fw']['network6']['infra']['server'] }}/128 scram-sha-256
|
||||
hostssl all all {{ hostvars['fw']['network4']['subnet']['lla'] }} scram-sha-256
|
||||
hostssl all all {{ hostvars['fw']['network6']['subnet']['lla'] }} scram-sha-256
|
||||
|
||||
# auth VM
|
||||
hostssl all all {{ hostvars['fw']['network4']['auth']['server'] }}/32 scram-sha-256
|
||||
hostssl all all {{ hostvars['fw']['network6']['auth']['server'] }}/128 scram-sha-256
|
||||
|
||||
# app VM (Applications, 192.168.10.13)
|
||||
hostssl all all {{ hostvars['fw']['network4']['app']['server'] }}/32 scram-sha-256
|
||||
hostssl all all {{ hostvars['fw']['network6']['app']['server'] }}/128 scram-sha-256
|
||||
@@ -0,0 +1,41 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# CUSTOMIZED OPTIONS
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# Add settings for extensions here
|
||||
# Listen_address
|
||||
listen_addresses = '*'
|
||||
# Max connections
|
||||
max_connections = 250
|
||||
# listen_port
|
||||
port = 5432
|
||||
|
||||
# SSL
|
||||
ssl = on
|
||||
ssl_ca_file = '/etc/ssl/postgresql/ilnmors_root_ca.crt'
|
||||
ssl_cert_file = '/etc/ssl/postgresql/postgresql.crt'
|
||||
ssl_key_file = '/etc/ssl/postgresql/postgresql.key'
|
||||
ssl_ciphers = 'HIGH:!aNULL:!MD5'
|
||||
ssl_prefer_server_ciphers = on
|
||||
|
||||
# log
|
||||
log_destination = 'stderr'
|
||||
log_checkpoints = on
|
||||
log_temp_files = 0
|
||||
log_min_duration_statement = 500
|
||||
|
||||
# IO
|
||||
track_io_timing = on
|
||||
|
||||
## immich_config
|
||||
shared_preload_libraries = 'vchord.so'
|
||||
search_path = '"$user", public'
|
||||
max_wal_size = 5GB
|
||||
shared_buffers = 512MB
|
||||
wal_compression = on
|
||||
work_mem = 16MB
|
||||
autovacuum_vacuum_scale_factor = 0.1
|
||||
autovacuum_analyze_scale_factor = 0.05
|
||||
autovacuum_vacuum_cost_limit = 1000
|
||||
effective_io_concurrency = 200
|
||||
random_page_cost = 1.2
|
||||
@@ -0,0 +1,36 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=PostgreSQL
|
||||
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=ilnmors.internal/{{ node['name'] }}/postgres:pg{{ version['containers']['postgresql'] }}-vectorchord{{ version['containers']['vectorchord'] }}
|
||||
|
||||
ContainerName=postgresql
|
||||
HostName=postgresql
|
||||
|
||||
PublishPort=5432:5432/tcp
|
||||
|
||||
Volume=%h/containers/postgresql/data:/var/lib/postgresql:rw
|
||||
Volume=%h/containers/postgresql/config:/config:ro
|
||||
Volume=%h/containers/postgresql/ssl:/etc/ssl/postgresql:ro
|
||||
Volume=%h/containers/postgresql/init:/docker-entrypoint-initdb.d/:ro
|
||||
Volume=%h/containers/postgresql/backups:/backups:rw
|
||||
|
||||
Environment="TZ=Asia/Seoul"
|
||||
# This option is only for init process, after init custom config file `pg_hba.conf` will control this option.
|
||||
Environment="POSTGRES_HOST_AUTH_METHOD=trust"
|
||||
|
||||
Exec=postgres -c 'config_file=/config/postgresql.conf' -c 'hba_file=/config/pg_hba.conf'
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
[Unit]
|
||||
Description=PostgreSQL Cluster Backup Service
|
||||
After=postgresql.service
|
||||
BindsTo=postgresql.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
||||
# logging
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
ExecStartPre=/usr/bin/podman exec postgresql sh -c "mkdir -p /backups/cluster && chown postgres:root /backups/cluster && chmod 770 /backups/cluster"
|
||||
|
||||
# Run the script
|
||||
ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c 'pg_dumpall -U postgres --schema-only | grep -v -E "CREATE ROLE postgres" > /backups/cluster/pg_cluster_$(date "+%%Y-%%m-%%d").sql'
|
||||
ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c "find /backups/cluster -maxdepth 1 -type f -mtime +7 -delete"
|
||||
ExecStart=/usr/bin/podman exec postgresql sh -c "chown -R postgres:root /backups/cluster && chmod 660 /backups/cluster/*"
|
||||
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Run PostgreSQL Cluster Backup service every day
|
||||
|
||||
[Timer]
|
||||
# Execute service after 1 min on booting
|
||||
OnBootSec=1min
|
||||
|
||||
# Execute service every day 00:00
|
||||
OnCalendar=*-*-* 00:00:00
|
||||
# Random time to postpone the timer
|
||||
RandomizedDelaySec=15min
|
||||
|
||||
# When timer is activated, Service also starts.
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description=PostgreSQL Data %i Backup Service
|
||||
After=postgresql.service
|
||||
BindsTo=postgresql.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
||||
# logging
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
ExecStartPre=/usr/bin/podman exec postgresql sh -c "mkdir -p /backups/%i && chown postgres:root /backups/%i && chmod 770 /backups/%i"
|
||||
|
||||
# Run the script
|
||||
ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c 'printf "\\connect %i_db\n" > /backups/%i/pg_%i_$(date "+%%Y-%%m-%%d").sql'
|
||||
ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c 'pg_dump -U postgres -d %i_db --data-only >> /backups/%i/pg_%i_$(date "+%%Y-%%m-%%d").sql'
|
||||
ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c "find /backups/%i -maxdepth 1 -type f -mtime +7 -delete"
|
||||
ExecStart=/usr/bin/podman exec postgresql sh -c "chown -R postgres:root /backups/%i && chmod 660 /backups/%i/*"
|
||||
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Run %i Data Backup service every day
|
||||
|
||||
[Timer]
|
||||
# Execute service after 1 min on booting
|
||||
OnBootSec=1min
|
||||
|
||||
# Execute service every day 00:00
|
||||
OnCalendar=*-*-* 00:00:00
|
||||
# Random time to postpone the timer
|
||||
RandomizedDelaySec=15min
|
||||
|
||||
# When timer is activated, Service also starts.
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1,32 @@
|
||||
# my global config
|
||||
global:
|
||||
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
|
||||
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
|
||||
# scrape_timeout is set to the global default (10s).
|
||||
|
||||
# Alertmanager configuration
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- static_configs:
|
||||
- targets:
|
||||
# - alertmanager:9093
|
||||
|
||||
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
|
||||
rule_files:
|
||||
- "/etc/prometheus/rules.yaml"
|
||||
|
||||
# A scrape configuration containing exactly one endpoint to scrape:
|
||||
# Here it's Prometheus itself.
|
||||
scrape_configs:
|
||||
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
|
||||
- job_name: "prometheus"
|
||||
# metrics_path defaults to '/metrics'
|
||||
scheme: "https"
|
||||
tls_config:
|
||||
ca_file: "/etc/ssl/prometheus/ilnmors_root_ca.crt"
|
||||
server_name: "{{ infra_uri['prometheus']['domain'] }}"
|
||||
static_configs:
|
||||
- targets: ["localhost:9090"]
|
||||
# The label name is added as a label `label_name=<label_value>` to any timeseries scraped from this config.
|
||||
labels:
|
||||
instance: "{{ node['name'] }}"
|
||||
@@ -0,0 +1,38 @@
|
||||
groups:
|
||||
- name: node_exporters_heartbeat
|
||||
rules:
|
||||
{% for instance in ['vmm', 'fw', 'infra', 'auth', 'app'] %}
|
||||
- alert: {{ instance }}_node_exporter_down
|
||||
expr: |
|
||||
(present_over_time(up{instance="{{ instance }}"}[5m]) or on() vector(0)) == 0
|
||||
for: 30s
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Exporter heartbeat is down: {{ instance }}"
|
||||
description: "{{ instance }} exporter is down for 5 mins"
|
||||
{% endfor %}
|
||||
- name: postgresql_heartbeat
|
||||
rules:
|
||||
- alert: Postgresql_Down
|
||||
expr: |
|
||||
(present_over_time(pg_up{instance="infra", job="postgres"}[5m]) or on() vector(0)) == 0
|
||||
for: 30s
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Postgresql Heartbeat Lost: postgresql"
|
||||
description: "postgresql node is down for 5 mins."
|
||||
- name: Certificate_expiry_check
|
||||
rules:
|
||||
{% for filename in ['root.crt', 'intermediate.crt', 'crowdsec.crt', 'blocky.crt', 'postgresql.crt', 'ldap.crt', 'prometheus.crt', 'loki.crt', 'dsm.crt'] %}
|
||||
- alert: {{ filename | replace('.', '_') }}_is_expired_soon
|
||||
expr: |
|
||||
max(x509_cert_not_after{filename="{{ filename }}"}) - time() < 2592000
|
||||
for: 1d
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "{{ filename }} is expired in 30 days"
|
||||
description: "{{ filename }} is expired in 30 days."
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,9 @@
|
||||
# Additionally, a certificate and a key file are needed.
|
||||
tls_server_config:
|
||||
cert_file: "/etc/ssl/prometheus/prometheus.crt"
|
||||
key_file: "/etc/ssl/prometheus/prometheus.key"
|
||||
|
||||
# Passwords are hashed with bcrypt: https://github.com/prometheus/exporter-toolkit/blob/master/docs/web-configuration.md#about-bcrypt
|
||||
#basic_auth_users:
|
||||
# alice: $2y$10$mDwo.lAisC94iLAyP81MCesa29IzH37oigHC/42V2pdJlUprsJPze
|
||||
# bob: $2y$10$hLqFl9jSjoAAy95Z/zw8Ye8wkdMBM8c5Bn1ptYqP/AXyV0.oy0S8m
|
||||
@@ -0,0 +1,38 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=Prometheus
|
||||
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/prom/prometheus:{{ version['containers']['prometheus'] }}
|
||||
|
||||
ContainerName=prometheus
|
||||
HostName=prometheus
|
||||
|
||||
PublishPort=9090:9090/tcp
|
||||
|
||||
Volume=%h/containers/prometheus/data:/prometheus:rw
|
||||
Volume=%h/containers/prometheus/etc:/etc/prometheus:ro
|
||||
Volume=%h/containers/prometheus/ssl:/etc/ssl/prometheus:ro
|
||||
|
||||
Environment="TZ=Asia/Seoul"
|
||||
|
||||
Exec=--config.file=/etc/prometheus/prometheus.yaml \
|
||||
--web.config.file=/etc/prometheus/web-config.yaml \
|
||||
--web.enable-remote-write-receiver \
|
||||
--storage.tsdb.path=/prometheus \
|
||||
--storage.tsdb.retention.time=30d \
|
||||
--storage.tsdb.retention.size=15GB \
|
||||
--storage.tsdb.wal-compression
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,26 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=x509-Exporter
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
Image=docker.io/enix/x509-certificate-exporter:{{ version['containers']['x509-exporter'] }}
|
||||
ContainerName=x509-exporter
|
||||
HostName=X509-exporter
|
||||
|
||||
Volume=%h/containers/x509-exporter/certs:/certs:ro
|
||||
|
||||
PublishPort=9793:9793
|
||||
|
||||
Exec=--listen-address :9793 --watch-dir=/certs
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,299 @@
|
||||
// The "name" and "job"
|
||||
// job > prometheus: which exporter / loki: which service
|
||||
// name > prometheus: which service
|
||||
// service_name > loki: which service
|
||||
// Metric
|
||||
//// Metric ouput
|
||||
prometheus.remote_write "prometheus" {
|
||||
endpoint {
|
||||
url = "https://{{ infra_uri['prometheus']['domain'] }}:{{ infra_uri['prometheus']['ports']['https'] }}/api/v1/write"
|
||||
}
|
||||
}
|
||||
|
||||
//// Metric relabel
|
||||
////// For node metrics
|
||||
prometheus.relabel "system_relabel" {
|
||||
forward_to = [prometheus.remote_write.prometheus.receiver]
|
||||
rule {
|
||||
target_label = "instance"
|
||||
replacement = "{{ node['name'] }}"
|
||||
}
|
||||
rule {
|
||||
source_labels = ["job"]
|
||||
regex = "integrations\\/(.+)"
|
||||
target_label = "job"
|
||||
replacement = "$1"
|
||||
}
|
||||
rule {
|
||||
source_labels = ["name"]
|
||||
regex = "(.+)\\.service"
|
||||
target_label = "name"
|
||||
replacement = "$1"
|
||||
}
|
||||
}
|
||||
|
||||
////// For service metrics
|
||||
prometheus.relabel "default_label" {
|
||||
forward_to = [prometheus.remote_write.prometheus.receiver]
|
||||
rule {
|
||||
target_label = "instance"
|
||||
replacement = "{{ node['name'] }}"
|
||||
}
|
||||
rule {
|
||||
source_labels = ["job"]
|
||||
regex = "prometheus\\.scrape\\.(.+)"
|
||||
target_label = "job"
|
||||
replacement = "$1"
|
||||
}
|
||||
rule {
|
||||
source_labels = ["job"]
|
||||
regex = "integrations\\/(.+)"
|
||||
target_label = "job"
|
||||
replacement = "$1"
|
||||
}
|
||||
}
|
||||
|
||||
//// Metric input
|
||||
////// For node metrics
|
||||
prometheus.exporter.unix "system" {
|
||||
enable_collectors = ["systemd", "cgroup", "processes", "cpu", "meminfo", "filesystem", "netdev"]
|
||||
filesystem {
|
||||
mount_points_exclude = "^/(sys|proc|dev|run|var/lib/docker/.+|var/lib/kubelet/.+)($|/)"
|
||||
fs_types_exclude = "^(tmpfs|devtmpfs|devfs|iso9660|overlay|aufs|squashfs)$"
|
||||
}
|
||||
}
|
||||
prometheus.scrape "system" {
|
||||
targets = prometheus.exporter.unix.system.targets
|
||||
forward_to = [prometheus.relabel.system_relabel.receiver]
|
||||
}
|
||||
|
||||
{% if node['name'] == 'fw' %}
|
||||
////// For Crowdsec metrics
|
||||
prometheus.scrape "crowdsec" {
|
||||
targets = [
|
||||
{ "__address__" = "{{ infra_uri['crowdsec']['domain'] }}:6060", "job" = "crowdsec" },
|
||||
{ "__address__" = "{{ infra_uri['crowdsec']['domain'] }}:60601", "job" = "crowdsec-bouncer" },
|
||||
]
|
||||
honor_labels = true
|
||||
forward_to = [prometheus.relabel.default_label.receiver]
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if node['name'] == 'infra' %}
|
||||
////// For postgresql metrics
|
||||
prometheus.exporter.postgres "postgresql" {
|
||||
data_source_names = [
|
||||
"postgres://alloy@{{ infra_uri['postgresql']['domain'] }}:{{ infra_uri['postgresql']['ports']['tcp'] }}/postgres?sslmode=verify-full",
|
||||
]
|
||||
}
|
||||
prometheus.scrape "postgresql" {
|
||||
targets = prometheus.exporter.postgres.postgresql.targets
|
||||
forward_to = [prometheus.relabel.default_label.receiver]
|
||||
}
|
||||
///// For certificates metrics
|
||||
prometheus.scrape "x509" {
|
||||
targets = [
|
||||
{ "__address__" = "{{ node['name'] }}.ilnmors.internal:9793" },
|
||||
]
|
||||
forward_to = [prometheus.relabel.default_label.receiver]
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if node['name'] in ['infra', 'auth', 'app'] %}
|
||||
////// For Input Caddy metrics
|
||||
prometheus.scrape "caddy" {
|
||||
targets = [
|
||||
{ "__address__" = "{{ node['name'] }}.ilnmors.internal:443" },
|
||||
]
|
||||
scheme = "https"
|
||||
forward_to = [prometheus.relabel.default_label.receiver]
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
// Log
|
||||
//// Logs output
|
||||
loki.write "loki" {
|
||||
endpoint {
|
||||
url = "https://{{ infra_uri['loki']['domain'] }}:{{ infra_uri['loki']['ports']['https'] }}/loki/api/v1/push"
|
||||
tenant_id = "ilnmors.internal"
|
||||
}
|
||||
}
|
||||
//// Logs relabel
|
||||
///// journal
|
||||
loki.relabel "journal_relabel" {
|
||||
forward_to = []
|
||||
rule {
|
||||
target_label = "instance"
|
||||
replacement = "{{ node['name'] }}"
|
||||
}
|
||||
// Default value
|
||||
rule {
|
||||
target_label = "job"
|
||||
replacement = "systemd-journal"
|
||||
}
|
||||
// if identifier exists
|
||||
rule {
|
||||
source_labels = ["__journal_syslog_identifier"]
|
||||
regex = "(.+)"
|
||||
target_label = "job"
|
||||
replacement = "$1"
|
||||
}
|
||||
// if systemd_unit exists
|
||||
rule {
|
||||
source_labels = ["__journal__systemd_unit"]
|
||||
regex = "(.+)\\.service"
|
||||
target_label = "job"
|
||||
replacement = "$1"
|
||||
}
|
||||
// if systemd_unit is "user@$UID"
|
||||
rule {
|
||||
source_labels = ["job"]
|
||||
regex = "user@\\d+"
|
||||
target_label = "job"
|
||||
replacement = "systemd-journal"
|
||||
}
|
||||
// if systemd_user_unit exists
|
||||
rule {
|
||||
source_labels = ["__journal__systemd_user_unit"]
|
||||
regex = "(.+)\\.service"
|
||||
target_label = "job"
|
||||
replacement = "$1"
|
||||
}
|
||||
rule {
|
||||
source_labels = ["__journal_priority_keyword"]
|
||||
target_label = "level"
|
||||
}
|
||||
}
|
||||
{% if node['name'] == "fw" %}
|
||||
loki.relabel "suricata_relabel" {
|
||||
forward_to = [loki.process.suricata_json.receiver]
|
||||
rule {
|
||||
target_label = "instance"
|
||||
replacement = "{{ node['name'] }}"
|
||||
}
|
||||
rule {
|
||||
target_label = "level"
|
||||
replacement = "info"
|
||||
}
|
||||
rule {
|
||||
target_label = "job"
|
||||
replacement = "suricata_eve"
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% if node['name'] == "auth" %}
|
||||
loki.relabel "caddy_relabel" {
|
||||
forward_to = [loki.process.caddy_json.receiver]
|
||||
rule {
|
||||
target_label = "instance"
|
||||
replacement = "{{ node['name'] }}"
|
||||
}
|
||||
rule {
|
||||
target_label = "level"
|
||||
replacement = "info"
|
||||
}
|
||||
rule {
|
||||
target_label = "job"
|
||||
replacement = "caddy_access"
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
//// Log parser
|
||||
///// journal
|
||||
loki.process "journal_parser" {
|
||||
forward_to = [loki.write.loki.receiver]
|
||||
// Severity parsing
|
||||
// If content of log includes "level" information, change the level
|
||||
stage.logfmt {
|
||||
mapping = {
|
||||
"content_level" = "level",
|
||||
}
|
||||
}
|
||||
stage.labels {
|
||||
values = {
|
||||
"level" = "content_level",
|
||||
}
|
||||
}
|
||||
// Add this section as parser for each service
|
||||
// common
|
||||
stage.match {
|
||||
selector = "{job=\"sshd\"}"
|
||||
stage.regex {
|
||||
expression = "Accepted \\w+ for (?P<user>\\w+) from (?P<ip>[\\d\\.]+)"
|
||||
}
|
||||
stage.labels {
|
||||
values = { "user" = "" }
|
||||
}
|
||||
}
|
||||
// infra
|
||||
{% if node['name'] == 'infra' %}
|
||||
// auth
|
||||
{% elif node['name'] == 'auth' %}
|
||||
// app
|
||||
{% elif node['name'] == 'app' %}
|
||||
{% endif %}
|
||||
}
|
||||
{% if node['name'] == "fw" %}
|
||||
////// suricata
|
||||
loki.process "suricata_json" {
|
||||
forward_to = [loki.write.loki.receiver]
|
||||
stage.json {
|
||||
expressions = {
|
||||
event_type = "event_type",
|
||||
src_ip = "src_ip",
|
||||
severity = "alert.severity",
|
||||
}
|
||||
}
|
||||
stage.labels {
|
||||
values = { event_type = "", severity = "" }
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% if node['name'] == "auth" %}
|
||||
////// caddy
|
||||
loki.process "caddy_json" {
|
||||
forward_to = [loki.write.loki.receiver]
|
||||
stage.json {
|
||||
expressions = {
|
||||
status = "status",
|
||||
method = "method",
|
||||
remote_ip = "remote_ip",
|
||||
duration = "duration",
|
||||
}
|
||||
}
|
||||
stage.labels {
|
||||
values = { status = "", method = "" }
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
//// Logs input
|
||||
////// journald
|
||||
loki.source.journal "systemd" {
|
||||
forward_to = [loki.process.journal_parser.receiver]
|
||||
// Temporary tags like "__journal__systemd_unit" is automatically removed when logs is passing "forward_to"
|
||||
// To relabel tags with temporary tags, relabel_rules command is necessary.
|
||||
relabel_rules = loki.relabel.journal_relabel.rules
|
||||
}
|
||||
|
||||
{% if node['name'] == 'fw' %}
|
||||
////// suricata
|
||||
local.file_match "suricata_logs" {
|
||||
path_targets = [{ "__path__" = "/var/log/suricata/eve.json", "instance" = "{{ node['name'] }}" }]
|
||||
}
|
||||
loki.source.file "suricata" {
|
||||
targets = local.file_match.suricata_logs.targets
|
||||
forward_to = [loki.relabel.suricata_relabel.receiver]
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if node['name'] == 'auth' %}
|
||||
////// caddy
|
||||
local.file_match "caddy_logs" {
|
||||
path_targets = [{ "__path__" = "/var/log/caddy/access.log", "instance" = "{{ node['name'] }}" }]
|
||||
}
|
||||
|
||||
loki.source.file "caddy" {
|
||||
targets = local.file_match.caddy_logs.targets
|
||||
forward_to = [loki.relabel.caddy_relabel.receiver]
|
||||
}
|
||||
{% endif %}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Suricata logs
|
||||
filenames:
|
||||
- /var/log/caddy/access.log
|
||||
labels:
|
||||
type: caddy
|
||||
@@ -0,0 +1,5 @@
|
||||
# Suricata logs
|
||||
filenames:
|
||||
- /var/log/suricata/eve.json
|
||||
labels:
|
||||
type: suricata
|
||||
@@ -0,0 +1,56 @@
|
||||
mode: nftables
|
||||
pid_dir: /var/run/
|
||||
update_frequency: 10s
|
||||
log_mode: file
|
||||
log_dir: /var/log/
|
||||
log_level: info
|
||||
log_compression: true
|
||||
log_max_size: 100
|
||||
log_max_backups: 3
|
||||
log_max_age: 30
|
||||
api_url: "https://{{ infra_uri['crowdsec']['domain'] }}:{{ infra_uri['crowdsec']['ports']['https'] }}"
|
||||
api_key: "{{ hostvars['console']['crowdsec']['bouncer']['fw'] }}"
|
||||
insecure_skip_verify: false
|
||||
disable_ipv6: false
|
||||
deny_action: DROP
|
||||
deny_log: false
|
||||
supported_decisions_types:
|
||||
- ban
|
||||
#to change log prefix
|
||||
#deny_log_prefix: "crowdsec: "
|
||||
#to change the blacklists name
|
||||
blacklists_ipv4: crowdsec-blacklists
|
||||
blacklists_ipv6: crowdsec6-blacklists
|
||||
#type of ipset to use
|
||||
ipset_type: nethash
|
||||
#if present, insert rule in those chains
|
||||
#iptables_chains:
|
||||
# - INPUT
|
||||
# - FORWARD
|
||||
# - OUTPUT
|
||||
# - DOCKER-USER
|
||||
|
||||
## nftables > table inet filter's set crowddsec-blacklists_ipv4,6 is needed
|
||||
nftables:
|
||||
ipv4:
|
||||
enabled: true
|
||||
set-only: true
|
||||
family: inet
|
||||
table: filter
|
||||
chain: global
|
||||
ipv6:
|
||||
enabled: true
|
||||
set-only: true
|
||||
family: inet
|
||||
table: filter
|
||||
chain: global
|
||||
# packet filter
|
||||
pf:
|
||||
# an empty string disables the anchor
|
||||
anchor_name: ""
|
||||
|
||||
# Crowdsec firewall bouncer cannot use "[::]" yet
|
||||
prometheus:
|
||||
enabled: true
|
||||
listen_addr: "::"
|
||||
listen_port: 60601
|
||||
@@ -0,0 +1,11 @@
|
||||
name: crowdsecurity/whitelists
|
||||
description: "Whitelist console/admin hosts only"
|
||||
whitelist:
|
||||
reason: "trusted admin hosts"
|
||||
ip:
|
||||
- "127.0.0.1"
|
||||
- "::1"
|
||||
- "{{ hostvars['fw']['network4']['console']['client'] }}"
|
||||
- "{{ hostvars['fw']['network4']['console']['wg'] }}"
|
||||
- "{{ hostvars['fw']['network6']['console']['client'] }}"
|
||||
- "{{ hostvars['fw']['network6']['console']['wg'] }}"
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Crowdsec Rule Update Service
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/cscli hub update
|
||||
ExecStart=/usr/bin/cscli hub upgrade
|
||||
ExecStartPost=/bin/systemctl restart crowdsec
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Daily Crowdsec Rule Update Timer
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 05:00:00
|
||||
Persistent=true
|
||||
RandomizedDelaySec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1,66 @@
|
||||
common:
|
||||
daemonize: true
|
||||
log_media: file
|
||||
log_level: info
|
||||
log_dir: /var/log/
|
||||
log_max_size: 20
|
||||
compress_logs: true
|
||||
log_max_files: 10
|
||||
working_dir: .
|
||||
config_paths:
|
||||
config_dir: /etc/crowdsec/
|
||||
data_dir: /var/lib/crowdsec/data/
|
||||
simulation_path: /etc/crowdsec/simulation.yaml
|
||||
hub_dir: /var/lib/crowdsec/hub/
|
||||
index_path: /var/lib/crowdsec/hub/.index.json
|
||||
notification_dir: /etc/crowdsec/notifications/
|
||||
plugin_dir: /usr/lib/crowdsec/plugins/
|
||||
crowdsec_service:
|
||||
acquisition_path: /etc/crowdsec/acquis.yaml
|
||||
acquisition_dir: /etc/crowdsec/acquis.d
|
||||
parser_routines: 1
|
||||
cscli:
|
||||
output: human
|
||||
color: auto
|
||||
db_config:
|
||||
log_level: info
|
||||
type: sqlite
|
||||
db_path: /var/lib/crowdsec/data/crowdsec.db
|
||||
#max_open_conns: 100
|
||||
#user:
|
||||
#password:
|
||||
#db_name:
|
||||
#host:
|
||||
#port:
|
||||
flush:
|
||||
max_items: 5000
|
||||
max_age: 7d
|
||||
plugin_config:
|
||||
user: nobody # plugin process would be ran on behalf of this user
|
||||
group: nogroup # plugin process would be ran on behalf of this group
|
||||
api:
|
||||
client:
|
||||
insecure_skip_verify: false
|
||||
credentials_path: /etc/crowdsec/local_api_credentials.yaml
|
||||
{% if node['name'] == 'fw' %}
|
||||
server:
|
||||
log_level: info
|
||||
listen_uri: "[::]:8080"
|
||||
profiles_path: /etc/crowdsec/profiles.yaml
|
||||
console_path: /etc/crowdsec/console.yaml
|
||||
online_client: # Central API credentials (to push signals and receive bad IPs)
|
||||
credentials_path: /etc/crowdsec/online_api_credentials.yaml
|
||||
trusted_ips: # IP ranges, or IPs which can have admin API access
|
||||
- ::1
|
||||
- 127.0.0.1
|
||||
- {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
- {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
tls:
|
||||
cert_file: /etc/crowdsec/ssl/crowdsec.crt
|
||||
key_file: /etc/crowdsec/ssl/crowdsec.key
|
||||
prometheus:
|
||||
enabled: true
|
||||
level: full
|
||||
listen_addr: "[::]"
|
||||
listen_port: 6060
|
||||
{% endif %}
|
||||
@@ -0,0 +1,3 @@
|
||||
url: https://{{ infra_uri['crowdsec']['domain'] }}:{{ infra_uri['crowdsec']['ports']['https'] }}
|
||||
login: {{ node['name'] }}
|
||||
password: {{ hostvars['console']['crowdsec']['machine'][node['name']] }}
|
||||
@@ -0,0 +1,49 @@
|
||||
[Unit]
|
||||
Description=Kopia backup service
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User=kopia
|
||||
Group=kopia
|
||||
|
||||
Type=oneshot
|
||||
|
||||
# logging
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
CapabilityBoundingSet=CAP_DAC_READ_SEARCH
|
||||
AmbientCapabilities=CAP_DAC_READ_SEARCH
|
||||
|
||||
ProtectSystem=strict
|
||||
ProtectHome=tmpfs
|
||||
InaccessiblePaths=/boot /root
|
||||
|
||||
{% if node['name'] == 'infra' %}
|
||||
BindReadOnlyPaths=/home/infra/containers/postgresql/backups
|
||||
{% elif node['name'] == 'app' %}
|
||||
BindReadOnlyPaths=/home/app/data
|
||||
{% endif %}
|
||||
# In root namescope, %u always bring 0
|
||||
BindPaths=/etc/kopia
|
||||
BindPaths=/etc/secrets/{{ kopia_uid }}
|
||||
BindPaths=/var/cache/kopia
|
||||
EnvironmentFile=/etc/secrets/{{ kopia_uid }}/kopia.env
|
||||
|
||||
ExecStartPre=/usr/bin/kopia repository connect server \
|
||||
--url=https://{{ infra_uri['kopia']['domain'] }}:{{ infra_uri['kopia']['ports']['https'] }} \
|
||||
--override-username={{ node['name'] }} \
|
||||
--override-hostname={{ node['name'] }}.ilnmors.internal
|
||||
|
||||
{% if node['name'] == 'infra' %}
|
||||
ExecStart=/usr/bin/kopia snapshot create \
|
||||
/home/infra/containers/postgresql/backups
|
||||
{% elif node['name'] == 'app' %}
|
||||
ExecStart=/usr/bin/kopia snapshot create \
|
||||
/home/app/data
|
||||
{% endif %}
|
||||
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Daily Kopia backup timer
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 03:00:00
|
||||
Persistent=true
|
||||
RandomizedDelaySec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1,5 @@
|
||||
KOPIA_PASSWORD={{ hostvars['console']['kopia']['user'][node['name']] }}
|
||||
KOPIA_CONFIG_PATH=/etc/kopia/repository.config
|
||||
KOPIA_CACHE_DIRECTORY=/var/cache/kopia
|
||||
KOPIA_LOG_DIR=/var/cache/kopia/logs
|
||||
KOPIA_CHECK_FOR_UPDATES=false
|
||||
@@ -0,0 +1,68 @@
|
||||
include "/etc/bind/acme.key";
|
||||
|
||||
options {
|
||||
directory "/var/cache/bind";
|
||||
|
||||
listen-on port 53 { {{ hostvars['fw']['network4']['bind']['server'] }}; };
|
||||
listen-on-v6 port 53 { {{ hostvars['fw']['network6']['bind']['server'] }}; };
|
||||
|
||||
// Authoritative DNS setting
|
||||
allow-recursion { none; };
|
||||
allow-transfer { none; };
|
||||
allow-update { none; };
|
||||
|
||||
dnssec-validation no;
|
||||
|
||||
check-names master warn;
|
||||
};
|
||||
|
||||
zone "ilnmors.internal." {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.ilnmors.internal";
|
||||
notify yes;
|
||||
// ACME-01 challenge policy. It allows only TXT record of subdomain update.
|
||||
update-policy {
|
||||
grant acme-key subdomain ilnmors.internal. TXT;
|
||||
};
|
||||
};
|
||||
|
||||
zone "1.168.192.in-addr.arpa" {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.1.168.192.in-addr.arpa";
|
||||
notify yes;
|
||||
};
|
||||
|
||||
zone "10.168.192.in-addr.arpa" {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.10.168.192.in-addr.arpa";
|
||||
notify yes;
|
||||
};
|
||||
|
||||
zone "0.0.0.0.0.0.0.0.1.0.0.0.0.0.d.f.ip6.arpa" {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.1.00df.ip6.arpa";
|
||||
notify yes;
|
||||
};
|
||||
|
||||
zone "0.0.0.0.0.0.0.0.0.1.0.0.0.0.d.f.ip6.arpa" {
|
||||
type primary;
|
||||
file "/var/lib/bind/db.10.00df.ip6.arpa";
|
||||
notify yes;
|
||||
};
|
||||
|
||||
zone "ilnmors.com." {
|
||||
//split horizon dns
|
||||
type primary;
|
||||
file "/var/lib/bind/db.ilnmors.com";
|
||||
notify yes;
|
||||
};
|
||||
|
||||
logging {
|
||||
channel default_log {
|
||||
stderr;
|
||||
severity info;
|
||||
};
|
||||
category default { default_log; };
|
||||
category config { default_log; };
|
||||
category queries { default_log; };
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
2026021201 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR fw.ilnmors.internal.
|
||||
1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR nas.ilnmors.internal.
|
||||
0.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR console.ilnmors.internal.
|
||||
@@ -0,0 +1,13 @@
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
2026021201 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
1 IN PTR fw.ilnmors.internal.
|
||||
11 IN PTR nas.ilnmors.internal.
|
||||
20 IN PTR console.ilnmors.internal.
|
||||
@@ -0,0 +1,17 @@
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
2026021201 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR fw.ilnmors.internal.
|
||||
2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR blocky.ilnmors.internal.
|
||||
3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR bind.ilnmors.internal.
|
||||
0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR vmm.ilnmors.internal.
|
||||
1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR infra.ilnmors.internal.
|
||||
2.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR auth.ilnmors.internal.
|
||||
3.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR app.ilnmors.internal.
|
||||
@@ -0,0 +1,17 @@
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
2026021201 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
1 IN PTR fw.ilnmors.internal.
|
||||
2 IN PTR blocky.ilnmors.internal.
|
||||
3 IN PTR bind.ilnmors.internal.
|
||||
10 IN PTR vmm.ilnmors.internal.
|
||||
11 IN PTR infra.ilnmors.internal.
|
||||
12 IN PTR auth.ilnmors.internal.
|
||||
13 IN PTR app.ilnmors.internal.
|
||||
@@ -0,0 +1,12 @@
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
2026021201 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
* IN A 192.168.10.12
|
||||
* IN AAAA fd00:10::12
|
||||
@@ -0,0 +1,40 @@
|
||||
$TTL 86400
|
||||
|
||||
@ IN SOA bind.ilnmors.internal. mail.ilnmors.internal. (
|
||||
2026021201 ; serial
|
||||
3600 ; refresh (1 hour)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
86400 ; minimum (1 day)
|
||||
)
|
||||
IN NS bind.ilnmors.internal.
|
||||
bind IN A 192.168.10.3
|
||||
bind IN AAAA fd00:10::3
|
||||
fw IN A 192.168.10.1
|
||||
fw IN AAAA fd00:10::1
|
||||
blocky IN A 192.168.10.2
|
||||
blocky IN AAAA fd00:10::2
|
||||
vmm IN A 192.168.10.10
|
||||
vmm IN AAAA fd00:10::10
|
||||
infra IN A 192.168.10.11
|
||||
infra IN AAAA fd00:10::11
|
||||
auth IN A 192.168.10.12
|
||||
auth IN AAAA fd00:10::12
|
||||
app IN A 192.168.10.13
|
||||
app IN AAAA fd00:10::13
|
||||
switch IN A 192.168.1.2
|
||||
nas IN A 192.168.1.11
|
||||
nas IN AAAA fd00:1::11
|
||||
console IN A 192.168.1.20
|
||||
console IN AAAA fd00:1::20
|
||||
printer IN A 192.168.1.101
|
||||
ntp IN CNAME fw.ilnmors.internal.
|
||||
crowdsec IN CNAME fw.ilnmors.internal.
|
||||
ca IN CNAME infra.ilnmors.internal.
|
||||
postgresql IN CNAME infra.ilnmors.internal.
|
||||
ldap IN CNAME infra.ilnmors.internal.
|
||||
prometheus IN CNAME infra.ilnmors.internal.
|
||||
loki IN CNAME infra.ilnmors.internal.
|
||||
grafana IN CNAME infra.ilnmors.internal.
|
||||
authelia IN CNAME auth.ilnmors.internal.
|
||||
*.app IN CNAME app.ilnmors.internal.
|
||||
@@ -0,0 +1,23 @@
|
||||
[Unit]
|
||||
Description=Blocky DNS Resolver
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User=blocky
|
||||
Group=blocky
|
||||
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
|
||||
ExecStart=/usr/local/bin/blocky --config /etc/blocky/config.yaml
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
|
||||
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=full
|
||||
ProtectHome=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,67 @@
|
||||
certFile: "/etc/blocky/ssl/blocky.crt"
|
||||
keyFile: "/etc/blocky/ssl/blocky.key"
|
||||
minTlsServeVersion: 1.2
|
||||
connectIPVersion: dual
|
||||
|
||||
ports:
|
||||
dns:
|
||||
- "{{ hostvars['fw']['network4']['blocky']['server'] }}:53"
|
||||
- "[{{ hostvars['fw']['network6']['blocky']['server'] }}]:53"
|
||||
tls:
|
||||
- "{{ hostvars['fw']['network4']['blocky']['server'] }}:853"
|
||||
- "[{{ hostvars['fw']['network6']['blocky']['server'] }}]:853"
|
||||
https:
|
||||
- "{{ hostvars['fw']['network4']['blocky']['server'] }}:443"
|
||||
- "[{{ hostvars['fw']['network6']['blocky']['server'] }}]:443"
|
||||
|
||||
log:
|
||||
level: info
|
||||
format: text
|
||||
timestamp: true
|
||||
privacy: false
|
||||
|
||||
upstreams:
|
||||
groups:
|
||||
default:
|
||||
- "tcp-tls:1.1.1.1:853"
|
||||
- "tcp-tls:1.0.0.1:853"
|
||||
- "tcp-tls:[2606:4700:4700::1111]:853"
|
||||
- "tcp-tls:[2606:4700:4700::1001]:853"
|
||||
|
||||
conditional:
|
||||
fallbackUpstream: false
|
||||
mapping:
|
||||
ilnmors.internal: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
|
||||
ilnmors.com: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
|
||||
1.168.192.in-addr.arpa: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
|
||||
10.168.192.in-addr.arpa: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
|
||||
0.0.0.0.0.0.0.0.1.0.0.0.0.0.d.f.ip6.arpa: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
|
||||
0.0.0.0.0.0.0.0.0.1.0.0.0.0.d.f.ip6.arpa: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
|
||||
vpn.ilnmors.com: "tcp-tls:1.1.1.1:853, tcp-tls:1.0.0.1:853, tcp-tls:[2606:4700:4700::1111]:853, tcp-tls:[2606:4700:4700::1001]:853"
|
||||
|
||||
blocking:
|
||||
blockType: nxDomain
|
||||
denylists:
|
||||
ads:
|
||||
# [ General ]
|
||||
- https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
|
||||
- https://big.oisd.nl
|
||||
- https://o0.pages.dev/Lite/domains.txt
|
||||
# [ Korean regional ]
|
||||
- https://raw.githubusercontent.com/yous/YousList/master/hosts.txt
|
||||
# [ Telemetry ]
|
||||
- https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt
|
||||
- https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/SmartTV.txt
|
||||
clientGroupsBlock:
|
||||
default:
|
||||
- ads
|
||||
|
||||
caching:
|
||||
minTime: 5m
|
||||
maxTime: 30m
|
||||
cacheTimeNegative: 0m
|
||||
prefetching: true
|
||||
|
||||
prometheus:
|
||||
enable: false
|
||||
path: /metrics
|
||||
@@ -0,0 +1,9 @@
|
||||
# 1. Access Control (IPv4)
|
||||
allow {{ hostvars['fw']['network4']['subnet']['client'] }}
|
||||
allow {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
allow {{ hostvars['fw']['network4']['subnet']['wg'] }}
|
||||
|
||||
# 2. Access Control (IPv6)
|
||||
allow {{ hostvars['fw']['network6']['subnet']['client'] }}
|
||||
allow {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
allow {{ hostvars['fw']['network6']['subnet']['wg'] }}
|
||||
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=DDNS Update Service
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
EnvironmentFile=/etc/secrets/%U/ddns.env
|
||||
|
||||
# Run the script
|
||||
ExecStart=/usr/local/bin/ddns.sh -d "ilnmors.com"
|
||||
@@ -0,0 +1,299 @@
|
||||
#!/bin/bash
|
||||
|
||||
## Change Log format as logfmt (refactoring)
|
||||
# ddns.sh -d domain [-t <ttl>] [-p] [-r] [-c]
|
||||
|
||||
# Default Information
|
||||
DOMAIN=""
|
||||
TTL=180
|
||||
C_TTL=86400
|
||||
PROXIED="false"
|
||||
DELETE_FLAG="false"
|
||||
CURRENT_IP=""
|
||||
|
||||
# These will be injected by systemd
|
||||
# ZONE_ID='.secret'
|
||||
# API_KEY='.secret'
|
||||
|
||||
# usage() function
|
||||
usage() {
|
||||
echo "Usage: $0 -d \"domain\" [-t \"ttl\"] [-p] [-r] [-c]"
|
||||
echo "-d <domain>: Specify the domain to update"
|
||||
echo "-t <ttl>: Specify the TTL(Time to live)"
|
||||
echo "-p: Specify the cloudflare proxy to use"
|
||||
echo "-r: Delete the DNS record"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Log function
|
||||
log() {
|
||||
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
local level="$1"
|
||||
local msg="$2"
|
||||
echo "time=\"$timestamp\" level=\"$level\" msg=\"$msg\" source=\"ddns.sh\"">&2
|
||||
}
|
||||
|
||||
# getopts to get arguments
|
||||
while getopts "d:t:pr" opt; do
|
||||
case $opt in
|
||||
d)
|
||||
DOMAIN="$OPTARG"
|
||||
;;
|
||||
t)
|
||||
TTL="$OPTARG"
|
||||
;;
|
||||
p)
|
||||
PROXIED="true"
|
||||
;;
|
||||
r)
|
||||
DELETE_FLAG="true"
|
||||
;;
|
||||
\?) # unknown options
|
||||
log "error" "Invalid option: -$OPTARG"
|
||||
usage
|
||||
;;
|
||||
:) # parameter required option
|
||||
log "error" "Option -$OPTARG requires an argument."
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Get option and move to parameters - This has no functional thing, because it only use arguments with parameters
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
# Check necessary options
|
||||
if [ -z "$DOMAIN" ]; then
|
||||
log "error" "-d option is required"
|
||||
usage
|
||||
fi
|
||||
|
||||
if ! [[ "$TTL" =~ ^[0-9]+$ ]] || [ "$TTL" -le 0 ]; then
|
||||
log "error" "-t option (ttl) requires a number above 0."
|
||||
usage
|
||||
fi
|
||||
|
||||
# Check necessary environment variables (Injected by systemd or shell)
|
||||
if [ -z "$ZONE_ID" ]; then
|
||||
log "error" "ZONE_ID is required via environment variable."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$API_KEY" ]; then
|
||||
log "error" "API_KEY is required via environment variable."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check package
|
||||
if ! command -v curl >/dev/null; then
|
||||
log "error" "curl is required"
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v jq >/dev/null; then
|
||||
log "error" "jq is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# API options
|
||||
URL="https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records"
|
||||
CONTENT_TYPE="Content-Type: application/json"
|
||||
AUTHORIZATION="Authorization: Bearer $API_KEY"
|
||||
|
||||
# Current IP
|
||||
CURRENT_IP=$( ip address show dev wan | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 )
|
||||
# Get current IP from external server when IP is private IP
|
||||
if [[ -z "$CURRENT_IP" || "$CURRENT_IP" =~ ^(10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.|127\.) ]]; then
|
||||
log "info" "IP from interface is private or empty. Fetching public IP..."
|
||||
CURRENT_IP=$(curl -sf "https://ifconfig.me") ||\
|
||||
CURRENT_IP=$(curl -sf "https://ifconfig.kr") ||\
|
||||
CURRENT_IP=$(curl -sf "https://api.ipify.org")
|
||||
fi
|
||||
if [ "$CURRENT_IP" == "" ]; then
|
||||
log "Error" "Can't get an IP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# DNS functions
|
||||
|
||||
# get_dns_record() function
|
||||
get_dns_record()
|
||||
{
|
||||
local type="$1"
|
||||
local name="$2"
|
||||
|
||||
local response="$(
|
||||
curl -s "$URL?type=$type&name=$name"\
|
||||
-H "$CONTENT_TYPE"\
|
||||
-H "$AUTHORIZATION")"
|
||||
if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
|
||||
log "error" "Can't get dns record by $response"
|
||||
exit 1
|
||||
else
|
||||
# return
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
|
||||
# create_dns_record() function
|
||||
create_dns_record()
|
||||
{
|
||||
local type="$1"
|
||||
local name="$2"
|
||||
local ttl="$3"
|
||||
local comment="$4"
|
||||
local content="$5"
|
||||
local response="$(
|
||||
curl -s "$URL"\
|
||||
-X POST\
|
||||
-H "$CONTENT_TYPE"\
|
||||
-H "$AUTHORIZATION"\
|
||||
-d "{
|
||||
\"name\": \"$name\",
|
||||
\"ttl\": $ttl,
|
||||
\"type\": \"$type\",
|
||||
\"comment\": \"$comment\",
|
||||
\"content\": \"$content\",
|
||||
\"proxied\": $PROXIED
|
||||
}")"
|
||||
if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
|
||||
log "error" "Can't create dns record by $response"
|
||||
exit 1
|
||||
else
|
||||
# return
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
|
||||
# update_dns_record() function
|
||||
update_dns_record()
|
||||
{
|
||||
local type="$1"
|
||||
local name="$2"
|
||||
local ttl="$3"
|
||||
local comment="$4"
|
||||
local content="$5"
|
||||
local id="$6"
|
||||
local response=$(
|
||||
curl -s "$URL/$id"\
|
||||
-X PUT\
|
||||
-H "$CONTENT_TYPE"\
|
||||
-H "$AUTHORIZATION"\
|
||||
-d "{
|
||||
\"name\": \"$name\",
|
||||
\"ttl\": $ttl,
|
||||
\"type\": \"$type\",
|
||||
\"comment\": \"$comment\",
|
||||
\"content\": \"$content\",
|
||||
\"proxied\": $PROXIED
|
||||
}")
|
||||
if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
|
||||
log "error" "Can't update dns record by $response"
|
||||
exit 1
|
||||
else
|
||||
#return
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
|
||||
# delete_dns_record() function
|
||||
delete_dns_record()
|
||||
{
|
||||
local type="$1"
|
||||
local id="$2"
|
||||
|
||||
local response=$(
|
||||
curl -s "$URL/$id"\
|
||||
-X DELETE\
|
||||
-H "$CONTENT_TYPE"\
|
||||
-H "$AUTHORIZATION"
|
||||
)
|
||||
if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
|
||||
log "error" "Can't delete dns record by $response"
|
||||
exit 1
|
||||
else
|
||||
# return
|
||||
echo "$response"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get DNS A, and CNAME record
|
||||
A_DNS_RECORD=$(get_dns_record "A" "$DOMAIN")
|
||||
S_DNS_RECORD=$(get_dns_record "cname" "*.$DOMAIN")
|
||||
W_DNS_RECORD=$(get_dns_record "cname" "www.$DOMAIN")
|
||||
|
||||
# Delete DNS record with Delete flag
|
||||
if [ "$DELETE_FLAG" == "true" ]; then
|
||||
FLAG="false"
|
||||
if [ "$(echo $A_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then
|
||||
A_DNS_ID="$(echo $A_DNS_RECORD | jq -r '.result[0].id')"
|
||||
delete_dns_record "A" "$A_DNS_ID"
|
||||
log "info" "root DNS record is deleted"
|
||||
FLAG="true"
|
||||
fi
|
||||
if [ "$(echo $S_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then
|
||||
S_DNS_ID="$(echo $S_DNS_RECORD | jq -r '.result[0].id')"
|
||||
delete_dns_record "cname" "$S_DNS_ID"
|
||||
log "info" "sub DNS record is deleted"
|
||||
FLAG="true"
|
||||
fi
|
||||
if [ "$(echo $W_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then
|
||||
W_DNS_ID="$(echo $W_DNS_RECORD | jq -r '.result[0].id')"
|
||||
delete_dns_record "cname" "$W_DNS_ID"
|
||||
log "info" "www DNS record is deleted"
|
||||
FLAG="true"
|
||||
fi
|
||||
if [ "$FLAG" == "false" ]; then
|
||||
log "info" "Nothing is Deleted. There are no DNS records"
|
||||
fi
|
||||
exit
|
||||
fi
|
||||
|
||||
# Create or update DNS A record
|
||||
if [ "$(echo $A_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then # root DNS record exist
|
||||
A_DNS_ID="$(echo $A_DNS_RECORD | jq -r '.result[0].id')"
|
||||
A_DNS_CONTENT="$(echo $A_DNS_RECORD | jq -r '.result[0].content')"
|
||||
A_DNS_TTL="$(echo $A_DNS_RECORD | jq -r '.result[0].ttl')"
|
||||
A_DNS_PROXIED="$(echo $A_DNS_RECORD | jq -r '.result[0].proxied')"
|
||||
if [ "$A_DNS_CONTENT" != $CURRENT_IP -o "$A_DNS_TTL" != "$TTL" -o "$A_DNS_PROXIED" != "$PROXIED" ]; then
|
||||
update_dns_record "A" "$DOMAIN" "$TTL" "$(date "+%Y-%m-%d %H:%M:%S"): root domain from ddns.sh" "$CURRENT_IP" "$A_DNS_ID"
|
||||
log "info" "Root DNS record is successfully changed Domain: $DOMAIN IP: $A_DNS_CONTENT to $CURRENT_IP TTL: $A_DNS_TTL to $TTL proxied: $A_DNS_PROXIED to $PROXIED"
|
||||
else
|
||||
log "info" "Root DNS record is not changed Domain: $DOMAIN IP: $CURRENT_IP TTL: $TTL proxied: $PROXIED"
|
||||
fi
|
||||
else # root DNS record does not exist
|
||||
create_dns_record "A" "$DOMAIN" "$TTL" "$(date "+%Y-%m-%d %H:%M:%S"): root domain from ddns.sh" "$CURRENT_IP"
|
||||
log "info" "Root DNS record is successfully created Domain: $DOMAIN IP: $CURRENT_IP TTL: $TTL proxied: $PROXIED"
|
||||
fi
|
||||
|
||||
# Create or update DNS CNAME records
|
||||
if [ "$(echo $S_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then # sub DNS record exist
|
||||
S_DNS_ID="$(echo $S_DNS_RECORD | jq -r '.result[0].id')"
|
||||
S_DNS_CONTENT="$(echo $S_DNS_RECORD | jq -r '.result[0].content')"
|
||||
S_DNS_TTL="$(echo $S_DNS_RECORD | jq -r '.result[0].ttl')"
|
||||
S_DNS_PROXIED="$(echo $S_DNS_RECORD | jq -r '.result[0].proxied')"
|
||||
if [ "$S_DNS_CONTENT" != "$DOMAIN" -o "$S_DNS_TTL" != "$C_TTL" -o "$S_DNS_PROXIED" != "$PROXIED" ]; then
|
||||
update_dns_record "cname" "*.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): sub domain from ddns.sh" "$DOMAIN" "$S_DNS_ID"
|
||||
log "info" "Sub DNS record is successfully changed Domain: $S_DNS_CONTENT to *.$DOMAIN cname: $DOMAIN TTL: $S_DNS_TTL to $C_TTL proxied: $S_DNS_PROXIED to $PROXIED"
|
||||
else
|
||||
log "info" "Sub DNS record is not changed Domain: *.$DOMAIN cname: $DOMAIN TTL: $C_TTL proxied: $PROXIED"
|
||||
fi
|
||||
else # sub DNS record does not exist
|
||||
create_dns_record "cname" "*.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): sub domain from ddns.sh" "$DOMAIN"
|
||||
log "info" "Sub DNS record is successfully created Domain: *.$DOMAIN cname: $DOMAIN TTL: $C_TTL proxied: $PROXIED"
|
||||
fi
|
||||
|
||||
if [ "$(echo $W_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then # www DNS record exist
|
||||
W_DNS_ID="$(echo $W_DNS_RECORD | jq -r '.result[0].id')"
|
||||
W_DNS_CONTENT="$(echo $W_DNS_RECORD | jq -r '.result[0].content')"
|
||||
W_DNS_TTL="$(echo $W_DNS_RECORD | jq -r '.result[0].ttl')"
|
||||
W_DNS_PROXIED="$(echo $W_DNS_RECORD | jq -r '.result[0].proxied')"
|
||||
if [ "$W_DNS_CONTENT" != "$DOMAIN" -o "$W_DNS_TTL" != "$C_TTL" -o "$W_DNS_PROXIED" != "$PROXIED" ]; then
|
||||
update_dns_record "cname" "www.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): www domain from ddns.sh" "$DOMAIN" "$W_DNS_ID"
|
||||
log "info" "www DNS record is successfully changed Domain: $W_DNS_CONTENT to www.$DOMAIN cname: $DOMAIN TTL: $W_DNS_TTL to $C_TTL proxied: $W_DNS_PROXIED to $PROXIED"
|
||||
else
|
||||
log "info" "www DNS record is not changed Domain: www.$DOMAIN cname: $DOMAIN TTL: $C_TTL proxied: $PROXIED"
|
||||
fi
|
||||
else # www DNS record does not exist
|
||||
create_dns_record "cname" "www.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): www domain from ddns.sh" "$DOMAIN"
|
||||
log "info" "www DNS record is successfully created Domain: www.$DOMAIN cname: $DOMAIN TTL: $C_TTL proxied: $PROXIED"
|
||||
fi
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Run DDNS update service every 5 minutes
|
||||
|
||||
[Timer]
|
||||
OnBootSec=1min
|
||||
OnUnitActiveSec=5min
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"Dhcp4": {
|
||||
"subnet4": [
|
||||
{
|
||||
"subnet": "{{ hostvars['fw']['network4']['subnet']['client'] }}",
|
||||
"pools" : [
|
||||
{
|
||||
"pool": "192.168.1.254-192.168.1.254"
|
||||
}
|
||||
],
|
||||
"option-data": [
|
||||
{
|
||||
"name": "routers",
|
||||
"data": "{{ hostvars['fw']['network4']['firewall']['client'] }}"
|
||||
},
|
||||
{
|
||||
"name": "domain-name-servers",
|
||||
"data": "{{ hostvars['fw']['network4']['blocky']['server'] }}"
|
||||
},
|
||||
{
|
||||
"name": "domain-name",
|
||||
"data": "ilnmors.internal."
|
||||
}
|
||||
],
|
||||
"reservations": [
|
||||
{
|
||||
"hw-address": "58:04:4f:18:6c:5e",
|
||||
"ip-address": "{{ hostvars['fw']['network4']['switch']['client'] }}",
|
||||
"hostname": "switch"
|
||||
},
|
||||
{
|
||||
"hw-address": "90:09:d0:65:a9:db",
|
||||
"ip-address": "{{ hostvars['fw']['network4']['nas']['client'] }}",
|
||||
"hostname": "nas"
|
||||
},
|
||||
{
|
||||
"hw-address": "d8:e2:df:ff:1b:d5",
|
||||
"ip-address": "{{ hostvars['fw']['network4']['console']['client'] }}",
|
||||
"hostname": "surface"
|
||||
},
|
||||
{
|
||||
"hw-address": "38:ca:84:94:5e:06",
|
||||
"ip-address": "{{ hostvars['fw']['network4']['printer']['client'] }}",
|
||||
"hostname": "printer"
|
||||
}
|
||||
],
|
||||
"id": 1,
|
||||
"interface": "client"
|
||||
},
|
||||
{
|
||||
"subnet": "{{ hostvars['fw']['network4']['subnet']['user'] }}",
|
||||
"pools" : [
|
||||
{
|
||||
"pool": "192.168.20.2-192.168.20.254"
|
||||
}
|
||||
],
|
||||
"option-data": [
|
||||
{
|
||||
"name": "routers",
|
||||
"data": "{{ hostvars['fw']['network4']['firewall']['user'] }}"
|
||||
},
|
||||
{
|
||||
"name": "domain-name-servers",
|
||||
"data": "{{ hostvars['fw']['network4']['blocky']['server'] }}"
|
||||
},
|
||||
{
|
||||
"name": "domain-name",
|
||||
"data": "ilnmors.internal."
|
||||
}
|
||||
],
|
||||
"id": 2,
|
||||
"interface": "user"
|
||||
}
|
||||
],
|
||||
"interfaces-config": {
|
||||
"interfaces": [
|
||||
"client",
|
||||
"user"
|
||||
],
|
||||
"dhcp-socket-type": "raw",
|
||||
"service-sockets-max-retries": 5,
|
||||
"service-sockets-require-all": true
|
||||
},
|
||||
"renew-timer": 1000,
|
||||
"rebind-timer": 2000,
|
||||
"valid-lifetime": 4000,
|
||||
"loggers": [
|
||||
{
|
||||
"name": "kea-dhcp4",
|
||||
"output_options": [
|
||||
{
|
||||
"output": "stdout"
|
||||
}
|
||||
],
|
||||
"severity": "INFO"
|
||||
}
|
||||
],
|
||||
"lease-database": {
|
||||
"type": "memfile",
|
||||
"persist": true,
|
||||
"name": "/var/lib/kea/kea-leases4.csv",
|
||||
"lfc-interval": 3600
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Stream events
|
||||
2210010 # SURICATA STREAM 3way handshake wrong seq wrong ack / TCP 3-way handshake in local networks
|
||||
2210021
|
||||
2210045
|
||||
# Wrong thread warning
|
||||
2210059
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user