init: atlas cluster v1
This commit is contained in:
commit
620231f5da
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
*.kdbx
|
||||
*.key
|
||||
*.priv
|
||||
*.env
|
||||
.terraform/
|
||||
*.tfstate*
|
||||
*.tfstate.backup
|
||||
*.tfvars
|
||||
.terraform.lock.hcl
|
||||
crash.log
|
||||
*.retry
|
||||
talos/clusterconfig/
|
||||
talos/kubeconfig
|
||||
|
||||
# Repomix
|
||||
repomix-output.xml
|
||||
talos/secrets.yaml
|
||||
|
||||
# Local Dynamic State
|
||||
docs/state/
|
||||
18
ansible/ansible.cfg
Normal file
18
ansible/ansible.cfg
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[defaults]
|
||||
inventory = inventory.yml
|
||||
remote_user = vyos
|
||||
host_key_checking = False
|
||||
retry_files_enabled = False
|
||||
interpreter_python = auto_silent
|
||||
deprecation_warnings = False
|
||||
|
||||
[privilege_escalation]
|
||||
become = False
|
||||
|
||||
[network_cli]
|
||||
ssh_type = paramiko
|
||||
|
||||
[paramiko_connection]
|
||||
host_key_auto_add = True
|
||||
record_host_keys = False
|
||||
look_for_keys = False
|
||||
9
ansible/files/technitium/settings.json
Normal file
9
ansible/files/technitium/settings.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"forwarders": [
|
||||
"9.9.9.9",
|
||||
"1.1.1.1"
|
||||
],
|
||||
"forwarderProtocol": "Tls",
|
||||
"dnssecValidation": true,
|
||||
"enableQueryLog": true
|
||||
}
|
||||
706
ansible/files/vyos/sing-box/config.json
Normal file
706
ansible/files/vyos/sing-box/config.json
Normal file
|
|
@ -0,0 +1,706 @@
|
|||
{
|
||||
"log": {
|
||||
"disabled": false,
|
||||
"level": "warn",
|
||||
"timestamp": false
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "udp",
|
||||
"tag": "atlas-dns",
|
||||
"server": "10.0.10.11",
|
||||
"server_port": 53
|
||||
},
|
||||
{
|
||||
"type": "fakeip",
|
||||
"tag": "fakeip-server",
|
||||
"inet4_range": "198.18.0.0/15",
|
||||
"inet6_range": "fc00::/18"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"action": "reject",
|
||||
"domain_suffix": "use-application-dns.net"
|
||||
},
|
||||
{
|
||||
"action": "route",
|
||||
"server": "atlas-dns",
|
||||
"domain_suffix": [
|
||||
"svo88.space"
|
||||
]
|
||||
},
|
||||
{
|
||||
"action": "route",
|
||||
"server": "fakeip-server",
|
||||
"rewrite_ttl": 60,
|
||||
"domain": [
|
||||
"fakeip.podkop.fyi",
|
||||
"ip.podkop.fyi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"domain_suffix": [
|
||||
"aistudio.google.com",
|
||||
"chatgpt.com",
|
||||
"claude.com",
|
||||
"claude.ai",
|
||||
"rutracker.cc",
|
||||
"udemy.com",
|
||||
"rutracker.org",
|
||||
"dub.co",
|
||||
"vyos.io",
|
||||
"vyos.net",
|
||||
"opentofu.org",
|
||||
"fontshare.com",
|
||||
"patreon.com",
|
||||
"getoutline.com",
|
||||
"appflowy.io",
|
||||
"notebooklm.google",
|
||||
"patreonusercontent.com",
|
||||
"anthropic.com",
|
||||
"media-amazon.com",
|
||||
"notion.com",
|
||||
"oxygenforensics.com",
|
||||
"forensicfocus.com",
|
||||
"apple.com",
|
||||
"cdn-apple.com",
|
||||
"reo.dev",
|
||||
"mintlify.com",
|
||||
"omarchy.org",
|
||||
"omacom.io",
|
||||
"omakub.org",
|
||||
"omamix.org",
|
||||
"dnsv1.com",
|
||||
"nll.coach",
|
||||
"office.net",
|
||||
"static.microsoft",
|
||||
"office.com",
|
||||
"msftauth.net",
|
||||
"pythonhosted.org",
|
||||
"vscode-unpkg.net",
|
||||
"notion.site",
|
||||
"imdb.com",
|
||||
"supersliv.biz",
|
||||
"kiraa.ai",
|
||||
"modrinth.com",
|
||||
"chunkbase.com",
|
||||
"minecraft.wiki",
|
||||
"fabricmc.net",
|
||||
"vimedocdn.com",
|
||||
"spotify.com",
|
||||
"mega.io",
|
||||
"mega.co.nz",
|
||||
"mega.nz",
|
||||
"unlocklocks.com",
|
||||
"ntc.party",
|
||||
"martview-forum.com",
|
||||
"gsmturkey.net",
|
||||
"makerworld.com",
|
||||
"audiomack.com",
|
||||
"beszel.dev",
|
||||
"ghfast.top",
|
||||
"virtualizationhowto.com",
|
||||
"ubuntu.com",
|
||||
"gnome.org",
|
||||
"archlinug.org",
|
||||
"usememos.com",
|
||||
"rackspace.com",
|
||||
"pkgbuild.com",
|
||||
"duckduckgo.com",
|
||||
"affine.pro",
|
||||
"docker.io",
|
||||
"docker.com",
|
||||
"cloudflarestorage.com",
|
||||
"production.cloudflare.docker.com",
|
||||
"zen-browser.app",
|
||||
"grapheneos.org",
|
||||
"androidauthority.com",
|
||||
"elhacker.info",
|
||||
"neetcode.io",
|
||||
"speedtest.net",
|
||||
"trendshift.io",
|
||||
"kali.org",
|
||||
"kali.download",
|
||||
"cdn-perfprod.com",
|
||||
"commandmasters.com",
|
||||
"netacad.com",
|
||||
"microsoft.com",
|
||||
"apphb.com",
|
||||
"vsassets.io",
|
||||
"visualstudio.com",
|
||||
"opencollective.com",
|
||||
"simpleicons.org",
|
||||
"vscode-cdn.net",
|
||||
"homarr.dev",
|
||||
"semrush.com",
|
||||
"cake.com",
|
||||
"clockify.me",
|
||||
"amazonaws.com",
|
||||
"nvidia.com",
|
||||
"githubusercontent.com",
|
||||
"trafficmanager.net",
|
||||
"cookielaw.org",
|
||||
"adobedtm.com",
|
||||
"amd.com",
|
||||
"custhelp.com",
|
||||
"geforce.com",
|
||||
"steamcommunity.com",
|
||||
"steamstatic.com",
|
||||
"continue.dev",
|
||||
"pinimg.com",
|
||||
"xda-developers.com",
|
||||
"xdaimages.com",
|
||||
"binance.com",
|
||||
"itsfoss.com",
|
||||
"tecmint.com",
|
||||
"medium.com",
|
||||
"gravatar.com",
|
||||
"contextly.com",
|
||||
"jsdelivr.net",
|
||||
"stripe.com",
|
||||
"stripe.network",
|
||||
"fastcomments.com",
|
||||
"akamai.net",
|
||||
"fastly.net",
|
||||
"sixthtone.com",
|
||||
"github.dev",
|
||||
"githubassets.com",
|
||||
"gitlab.io",
|
||||
"github.io",
|
||||
"zimaspace.com",
|
||||
"polymaker.com",
|
||||
"qidi3d.com",
|
||||
"videowise.com",
|
||||
"kingroon.com",
|
||||
"qiditech.com",
|
||||
"mutecmutes.com",
|
||||
"flow-content.google",
|
||||
"googleusercontent.com",
|
||||
"warburton-usa.com",
|
||||
"ebay.com",
|
||||
"bambulab.com",
|
||||
"openqidi.com",
|
||||
"tinkercad.com",
|
||||
"yeggi.com",
|
||||
"ttvnw.net",
|
||||
"jtvnw.net",
|
||||
"twitch.tv"
|
||||
],
|
||||
"action": "route",
|
||||
"server": "fakeip-server",
|
||||
"rewrite_ttl": 60
|
||||
},
|
||||
{
|
||||
"rule_set": [
|
||||
"Main-telegram-community-ruleset",
|
||||
"Main-cloudfront-community-ruleset",
|
||||
"Main-digitalocean-community-ruleset",
|
||||
"Main-ovh-community-ruleset",
|
||||
"Main-hetzner-community-ruleset",
|
||||
"Main-github-community-ruleset",
|
||||
"Main-hodca-community-ruleset",
|
||||
"Main-google_play-community-ruleset",
|
||||
"Main-google_ai-community-ruleset",
|
||||
"Main-cloudflare-community-ruleset",
|
||||
"Main-hdrezka-community-ruleset",
|
||||
"Main-twitter-community-ruleset",
|
||||
"Main-meta-community-ruleset",
|
||||
"Main-news-community-ruleset"
|
||||
],
|
||||
"action": "route",
|
||||
"server": "fakeip-server",
|
||||
"rewrite_ttl": 60
|
||||
},
|
||||
{
|
||||
"domain_suffix": [
|
||||
"reddit.com",
|
||||
"ozon.ru",
|
||||
"vtb.ru",
|
||||
"vtb.com",
|
||||
"vtb.tech",
|
||||
"sbpvtb.ru",
|
||||
"multicarta.ru",
|
||||
"nspk.ru",
|
||||
"xn--90ad4b.xn--p1ai",
|
||||
"gosuslugi.ru"
|
||||
],
|
||||
"action": "route",
|
||||
"server": "atlas-dns",
|
||||
"rewrite_ttl": 60
|
||||
},
|
||||
{
|
||||
"rule_set": "direct-russia_inside-community-ruleset",
|
||||
"action": "route",
|
||||
"server": "atlas-dns",
|
||||
"rewrite_ttl": 60
|
||||
}
|
||||
],
|
||||
"final": "atlas-dns",
|
||||
"strategy": "prefer_ipv4",
|
||||
"independent_cache": true
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tun",
|
||||
"tag": "tproxy-in",
|
||||
"address": [
|
||||
"172.19.0.1/30"
|
||||
],
|
||||
"auto_route": true,
|
||||
"strict_route": false,
|
||||
"route_address": [
|
||||
"198.18.0.0/15",
|
||||
"91.108.0.0/16",
|
||||
"149.154.160.0/20"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "dns-in",
|
||||
"listen": "127.0.0.42",
|
||||
"listen_port": 53
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "service-mixed-in",
|
||||
"listen": "127.0.0.1",
|
||||
"listen_port": 4534
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out"
|
||||
},
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "bypass-out"
|
||||
},
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "Main-1-out",
|
||||
"server": "153.76.194.24",
|
||||
"server_port": 443,
|
||||
"uuid": "3ce63e78-ada7-4855-add1-15ad5b9ac3bf",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "ng.w.svo88.space",
|
||||
"utls": {
|
||||
"enabled": true,
|
||||
"fingerprint": "edge"
|
||||
},
|
||||
"reality": {
|
||||
"enabled": true,
|
||||
"public_key": "csLZ_3t_NswOEGV64PP_tTA9ne_4_R6YD95uprPAfis",
|
||||
"short_id": "c395"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "urltest",
|
||||
"tag": "Main-urltest-cfg052898-out",
|
||||
"outbounds": [
|
||||
"Main-1-out"
|
||||
],
|
||||
"url": "https://captive.apple.com",
|
||||
"interval": "1m",
|
||||
"tolerance": 50
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "Main-out",
|
||||
"outbounds": [
|
||||
"Main-1-out",
|
||||
"Main-urltest-cfg052898-out"
|
||||
],
|
||||
"default": "Main-urltest-cfg052898-out"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"action": "sniff",
|
||||
"inbound": [
|
||||
"tproxy-in",
|
||||
"dns-in"
|
||||
]
|
||||
},
|
||||
{
|
||||
"action": "hijack-dns",
|
||||
"port": 53
|
||||
},
|
||||
{
|
||||
"action": "hijack-dns",
|
||||
"protocol": "dns"
|
||||
},
|
||||
{
|
||||
"action": "reject",
|
||||
"inbound": "tproxy-in",
|
||||
"protocol": "quic"
|
||||
},
|
||||
{
|
||||
"action": "route",
|
||||
"inbound": [
|
||||
"tproxy-in"
|
||||
],
|
||||
"outbound": "Main-out",
|
||||
"domain": "ip.podkop.fyi"
|
||||
},
|
||||
{
|
||||
"action": "route",
|
||||
"inbound": [
|
||||
"tproxy-in"
|
||||
],
|
||||
"outbound": "Main-out",
|
||||
"domain_suffix": [
|
||||
"aistudio.google.com",
|
||||
"chatgpt.com",
|
||||
"claude.com",
|
||||
"claude.ai",
|
||||
"rutracker.cc",
|
||||
"udemy.com",
|
||||
"rutracker.org",
|
||||
"dub.co",
|
||||
"vyos.io",
|
||||
"vyos.net",
|
||||
"opentofu.org",
|
||||
"fontshare.com",
|
||||
"patreon.com",
|
||||
"getoutline.com",
|
||||
"appflowy.io",
|
||||
"notebooklm.google",
|
||||
"patreonusercontent.com",
|
||||
"anthropic.com",
|
||||
"media-amazon.com",
|
||||
"notion.com",
|
||||
"oxygenforensics.com",
|
||||
"forensicfocus.com",
|
||||
"apple.com",
|
||||
"cdn-apple.com",
|
||||
"reo.dev",
|
||||
"mintlify.com",
|
||||
"omarchy.org",
|
||||
"omacom.io",
|
||||
"omakub.org",
|
||||
"omamix.org",
|
||||
"dnsv1.com",
|
||||
"nll.coach",
|
||||
"office.net",
|
||||
"static.microsoft",
|
||||
"office.com",
|
||||
"msftauth.net",
|
||||
"pythonhosted.org",
|
||||
"vscode-unpkg.net",
|
||||
"notion.site",
|
||||
"imdb.com",
|
||||
"supersliv.biz",
|
||||
"kiraa.ai",
|
||||
"modrinth.com",
|
||||
"chunkbase.com",
|
||||
"minecraft.wiki",
|
||||
"fabricmc.net",
|
||||
"vimedocdn.com",
|
||||
"spotify.com",
|
||||
"mega.io",
|
||||
"mega.co.nz",
|
||||
"mega.nz",
|
||||
"unlocklocks.com",
|
||||
"ntc.party",
|
||||
"martview-forum.com",
|
||||
"gsmturkey.net",
|
||||
"makerworld.com",
|
||||
"audiomack.com",
|
||||
"beszel.dev",
|
||||
"ghfast.top",
|
||||
"virtualizationhowto.com",
|
||||
"ubuntu.com",
|
||||
"gnome.org",
|
||||
"archlinug.org",
|
||||
"usememos.com",
|
||||
"rackspace.com",
|
||||
"pkgbuild.com",
|
||||
"duckduckgo.com",
|
||||
"affine.pro",
|
||||
"docker.io",
|
||||
"docker.com",
|
||||
"cloudflarestorage.com",
|
||||
"production.cloudflare.docker.com",
|
||||
"zen-browser.app",
|
||||
"grapheneos.org",
|
||||
"androidauthority.com",
|
||||
"elhacker.info",
|
||||
"neetcode.io",
|
||||
"speedtest.net",
|
||||
"trendshift.io",
|
||||
"kali.org",
|
||||
"kali.download",
|
||||
"cdn-perfprod.com",
|
||||
"commandmasters.com",
|
||||
"netacad.com",
|
||||
"microsoft.com",
|
||||
"apphb.com",
|
||||
"vsassets.io",
|
||||
"visualstudio.com",
|
||||
"opencollective.com",
|
||||
"simpleicons.org",
|
||||
"vscode-cdn.net",
|
||||
"homarr.dev",
|
||||
"semrush.com",
|
||||
"cake.com",
|
||||
"clockify.me",
|
||||
"amazonaws.com",
|
||||
"nvidia.com",
|
||||
"githubusercontent.com",
|
||||
"trafficmanager.net",
|
||||
"cookielaw.org",
|
||||
"adobedtm.com",
|
||||
"amd.com",
|
||||
"custhelp.com",
|
||||
"geforce.com",
|
||||
"steamcommunity.com",
|
||||
"steamstatic.com",
|
||||
"continue.dev",
|
||||
"pinimg.com",
|
||||
"xda-developers.com",
|
||||
"xdaimages.com",
|
||||
"binance.com",
|
||||
"itsfoss.com",
|
||||
"tecmint.com",
|
||||
"medium.com",
|
||||
"gravatar.com",
|
||||
"contextly.com",
|
||||
"jsdelivr.net",
|
||||
"stripe.com",
|
||||
"stripe.network",
|
||||
"fastcomments.com",
|
||||
"akamai.net",
|
||||
"fastly.net",
|
||||
"sixthtone.com",
|
||||
"github.dev",
|
||||
"githubassets.com",
|
||||
"gitlab.io",
|
||||
"github.io",
|
||||
"zimaspace.com",
|
||||
"polymaker.com",
|
||||
"qidi3d.com",
|
||||
"videowise.com",
|
||||
"kingroon.com",
|
||||
"qiditech.com",
|
||||
"mutecmutes.com",
|
||||
"flow-content.google",
|
||||
"googleusercontent.com",
|
||||
"warburton-usa.com",
|
||||
"ebay.com",
|
||||
"bambulab.com",
|
||||
"openqidi.com",
|
||||
"tinkercad.com",
|
||||
"yeggi.com",
|
||||
"ttvnw.net",
|
||||
"jtvnw.net",
|
||||
"twitch.tv"
|
||||
],
|
||||
"ip_cidr": [
|
||||
"194.87.55.26",
|
||||
"91.108.0.0/16",
|
||||
"149.154.160.0/20"
|
||||
],
|
||||
"rule_set": [
|
||||
"Main-telegram-community-ruleset",
|
||||
"Main-cloudfront-community-ruleset",
|
||||
"Main-digitalocean-community-ruleset",
|
||||
"Main-ovh-community-ruleset",
|
||||
"Main-hetzner-community-ruleset",
|
||||
"Main-github-community-ruleset",
|
||||
"Main-hodca-community-ruleset",
|
||||
"Main-google_play-community-ruleset",
|
||||
"Main-google_ai-community-ruleset",
|
||||
"Main-cloudflare-community-ruleset",
|
||||
"Main-hdrezka-community-ruleset",
|
||||
"Main-twitter-community-ruleset",
|
||||
"Main-meta-community-ruleset",
|
||||
"Main-news-community-ruleset"
|
||||
]
|
||||
},
|
||||
{
|
||||
"action": "route",
|
||||
"inbound": [
|
||||
"tproxy-in"
|
||||
],
|
||||
"outbound": "bypass-out",
|
||||
"domain_suffix": [
|
||||
"reddit.com",
|
||||
"ozon.ru",
|
||||
"vtb.ru",
|
||||
"vtb.com",
|
||||
"vtb.tech",
|
||||
"sbpvtb.ru",
|
||||
"multicarta.ru",
|
||||
"nspk.ru",
|
||||
"xn--90ad4b.xn--p1ai",
|
||||
"gosuslugi.ru"
|
||||
],
|
||||
"ip_cidr": [
|
||||
"195.242.82.0/23",
|
||||
"185.179.144.0/22",
|
||||
"212.11.144.0/21"
|
||||
],
|
||||
"rule_set": [
|
||||
"direct-russia_inside-community-ruleset",
|
||||
"inline-custom-c73fec97249a-ruleset"
|
||||
]
|
||||
},
|
||||
{
|
||||
"action": "route",
|
||||
"inbound": "service-mixed-in",
|
||||
"outbound": "Main-out"
|
||||
}
|
||||
],
|
||||
"rule_set": [
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-telegram-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/telegram.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-cloudfront-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/cloudfront.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-digitalocean-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/digitalocean.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-ovh-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/ovh.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-hetzner-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/hetzner.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-github-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/github.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-hodca-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/hodca.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-google_play-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/google_play.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-google_ai-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/google_ai.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-cloudflare-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/cloudflare.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-hdrezka-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/hdrezka.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-twitter-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/twitter.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-meta-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/meta.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "Main-news-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/news.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "direct-russia_inside-community-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/itdoginfo/allow-domains/releases/latest/download/russia_inside.srs",
|
||||
"update_interval": "1d",
|
||||
"download_detour": "Main-out"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "inline-custom-c73fec97249a-ruleset",
|
||||
"format": "binary",
|
||||
"url": "https://github.com/lyc8503/sing-box-rules/raw/rule-set-geoip/geoip-ru.srs",
|
||||
"download_detour": "Main-out",
|
||||
"update_interval": "1d"
|
||||
}
|
||||
],
|
||||
"final": "direct-out",
|
||||
"auto_detect_interface": true,
|
||||
"default_domain_resolver": "atlas-dns",
|
||||
"default_mark": 134217728
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"path": "/etc/sing-box/cache.db",
|
||||
"store_fakeip": true
|
||||
},
|
||||
"clash_api": {
|
||||
"external_controller": "0.0.0.0:9090",
|
||||
"external_ui": "ui"
|
||||
}
|
||||
}
|
||||
}
|
||||
150
ansible/files/vyos/zapret/config
Executable file
150
ansible/files/vyos/zapret/config
Executable file
|
|
@ -0,0 +1,150 @@
|
|||
# this file is included from init scripts
|
||||
# change values here
|
||||
|
||||
# can help in case /tmp has not enough space
|
||||
#TMPDIR=/opt/zapret/tmp
|
||||
|
||||
# redefine user for zapret daemons. required on Keenetic
|
||||
WS_USER="daemon"
|
||||
|
||||
# override firewall type : iptables,nftables,ipfw
|
||||
FWTYPE=nftables
|
||||
|
||||
# nftables only : set this to 0 to use pre-nat mode. default is post-nat.
|
||||
# pre-nat mode disables some bypass techniques for forwarded traffic but allows to see client IP addresses in debug log
|
||||
POSTNAT=1
|
||||
|
||||
# options for ipsets
|
||||
# maximum number of elements in sets. also used for nft sets
|
||||
SET_MAXELEM=522288
|
||||
|
||||
# too low hashsize can cause memory allocation errors on low RAM systems , even if RAM is enough
|
||||
# too large hashsize will waste lots of RAM
|
||||
IPSET_OPT="hashsize 262144 maxelem $SET_MAXELEM"
|
||||
|
||||
# dynamically generate additional ip. $1 = ipset/nfset/table name
|
||||
#IPSET_HOOK="/etc/zapret.ipset.hook"
|
||||
|
||||
# options for ip2net. "-4" or "-6" auto added by ipset create script
|
||||
IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4"
|
||||
IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5"
|
||||
|
||||
# options for auto hostlist
|
||||
# NOTE : in order for these adjustment to work it's required to redirect enough starting packets
|
||||
# NOTE : set PKT_IN, PKT_OUT variables appropriately
|
||||
AUTOHOSTLIST_INCOMING_MAXSEQ=4096
|
||||
AUTOHOSTLIST_RETRANS_MAXSEQ=32768
|
||||
AUTOHOSTLIST_RETRANS_RESET=1
|
||||
AUTOHOSTLIST_RETRANS_THRESHOLD=3
|
||||
AUTOHOSTLIST_FAIL_THRESHOLD=3
|
||||
AUTOHOSTLIST_FAIL_TIME=60
|
||||
AUTOHOSTLIST_UDP_IN=1
|
||||
AUTOHOSTLIST_UDP_OUT=4
|
||||
# 1 = debug autohostlist positives to ipset/zapret-hosts-auto-debug.log
|
||||
AUTOHOSTLIST_DEBUGLOG=0
|
||||
|
||||
# number of parallel threads for domain list resolves
|
||||
MDIG_THREADS=30
|
||||
# EAI_AGAIN retries
|
||||
MDIG_EAGAIN=10
|
||||
# delay between EAI_AGAIN retries (ms)
|
||||
MDIG_EAGAIN_DELAY=500
|
||||
|
||||
# ipset/*.sh can compress large lists
|
||||
GZIP_LISTS=0
|
||||
|
||||
# command to reload ip/host lists after update
|
||||
# comment or leave empty for auto backend selection : ipset or ipfw if present
|
||||
# on BSD systems with PF no auto reloading happens. you must provide your own command
|
||||
# set to "-" to disable reload
|
||||
#LISTS_RELOAD="pfctl -f /etc/pf.conf"
|
||||
|
||||
# none,ipset,hostlist,autohostlist
|
||||
MODE_FILTER=hostlist
|
||||
|
||||
# mark bit used by nfqws to prevent loop
|
||||
DESYNC_MARK=0x40000000
|
||||
DESYNC_MARK_POSTNAT=0x20000000
|
||||
|
||||
|
||||
# do not pass outgoing traffic to tpws/nfqws not marked with this bit
|
||||
# this setting allows to write your own rules to limit traffic that should be fooled
|
||||
# for example based on source IP or incoming interface name
|
||||
# no filter if not defined
|
||||
FILTER_MARK=""
|
||||
|
||||
|
||||
NFQWS2_ENABLE=1
|
||||
|
||||
# redirect outgoing traffic with connbytes limiter applied in both directions.
|
||||
NFQWS2_PORTS_TCP="443,2053,2083,2087,2096,8443"
|
||||
NFQWS2_PORTS_UDP="443,19294-19344,50000-65535"
|
||||
|
||||
# PKT_OUT means connbytes dir original
|
||||
# PKT_IN means connbytes dir reply
|
||||
NFQWS2_TCP_PKT_OUT="20"
|
||||
NFQWS2_TCP_PKT_IN="10"
|
||||
NFQWS2_UDP_PKT_OUT="5"
|
||||
NFQWS2_UDP_PKT_IN="3"
|
||||
|
||||
# redirect outgoing traffic without connbytes limiter and incoming with connbytes limiter
|
||||
# normally it's needed only for stateless DPI that matches every packet in a single TCP session
|
||||
# typical example are plain HTTP keep alives
|
||||
# this mode can be very CPU consuming. enable with care !
|
||||
NFQWS2_PORTS_TCP_KEEPALIVE=""
|
||||
NFQWS2_PORTS_UDP_KEEPALIVE=""
|
||||
|
||||
# use <HOSTLIST> and <HOSTLIST_NOAUTO> placeholders to engage standard hostlists and autohostlist in ipset dir
|
||||
# hostlist markers are replaced to empty string if MODE_FILTER does not satisfy
|
||||
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
|
||||
NFQWS2_OPT="--blob=quic_google:@/opt/zapret2/files/fake/quic_initial_www_google_com.bin --blob=tls_google:@/opt/zapret2/files/fake/tls_clienthello_www_google_com.bin --name=Quic --filter-udp=443 --filter-l7=quic --hostlist=/opt/zapret2/ipset/zapret-hosts-user.txt --payload=quic_initial --lua-desync=fake:blob=quic_google:repeats=6 --new --name=Google --filter-tcp=443 --filter-l7=tls --hostlist=/opt/zapret2/ipset/zapret-hosts-user.txt --payload=tls_client_hello --lua-desync=hostfakesplit:repeats=4:tcp_ts=-600000:host=www.google.com:ip_id=zero"
|
||||
DISABLE_CUSTOM=1
|
||||
|
||||
# FlowOffload mode : donttouch,none,software,hardware
|
||||
FLOWOFFLOAD=none
|
||||
|
||||
# openwrt: specify networks to be treated as LAN. default is "lan"
|
||||
#OPENWRT_LAN="lan lan2 lan3"
|
||||
|
||||
# openwrt: specify networks to be treated as WAN. default wans are interfaces with default route
|
||||
#OPENWRT_WAN4="wan vpn"
|
||||
#OPENWRT_WAN6="wan6 vpn6"
|
||||
|
||||
# for routers based on desktop linux and macos. has no effect in openwrt.
|
||||
# CHOOSE LAN and optinally WAN/WAN6 NETWORK INTERFACES
|
||||
# or leave them commented if its not router
|
||||
# it's possible to specify multiple interfaces like this : IFACE_WAN="eth0 eth1 eth2"
|
||||
# if IFACE_WAN6 is not defined it take the value of IFACE_WAN
|
||||
#IFACE_WAN=eth1
|
||||
#IFACE_WAN6="ipsec0 wireguard0 he_net"
|
||||
|
||||
# should start/stop command of init scripts apply firewall rules ?
|
||||
# not applicable to openwrt with firewall3+iptables
|
||||
INIT_APPLY_FW=1
|
||||
|
||||
# firewall apply hooks
|
||||
#INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret2.hook.pre_up"
|
||||
#INIT_FW_POST_UP_HOOK="/etc/firewall.zapret2.hook.post_up"
|
||||
#INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret2.hook.pre_down"
|
||||
#INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret2.hook.post_down"
|
||||
|
||||
# do not work with ipv4
|
||||
DISABLE_IPV4=0
|
||||
|
||||
# do not work with ipv6
|
||||
DISABLE_IPV6=1
|
||||
|
||||
# drop icmp time exceeded messages for nfqws tampered connections
|
||||
# in POSTNAT mode this can interfere with default mtr/traceroute in tcp or udp mode. use source port not redirected to nfqws
|
||||
# set to 0 if you are not expecting connection breakage due to icmp in response to TCP SYN or UDP
|
||||
FILTER_TTL_EXPIRED_ICMP=1
|
||||
|
||||
# select which init script will be used to get ip or host list
|
||||
# possible values : get_user.sh get_antizapret.sh get_combined.sh get_reestr.sh get_hostlist.sh
|
||||
# comment if not required
|
||||
#GETLIST=get_antizapret_domains.sh
|
||||
|
||||
|
||||
DAEMON_LOG_ENABLE=0
|
||||
DAEMON_LOG_SIZE_MAX=2000
|
||||
DAEMON_LOG_FILE="/tmp/zapret2+<DAEMON_NAME>+<DAEMON_IDNUM>+<DAEMON_CFGNAME>.log"
|
||||
198
ansible/files/vyos/zapret/ipset/zapret-hosts-google.txt
Normal file
198
ansible/files/vyos/zapret/ipset/zapret-hosts-google.txt
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
cdn.youtube.com
|
||||
fonts.googleapis.com
|
||||
fonts.gstatic.com
|
||||
ggpht.com
|
||||
googleapis.com
|
||||
googleusercontent.com
|
||||
googlevideo.com
|
||||
i.ytimg.com
|
||||
i9.ytimg.com
|
||||
jnn-pa.googleapis.com
|
||||
kids.youtube.com
|
||||
m.youtube.com
|
||||
manifest.googlevideo.com
|
||||
music.youtube.com
|
||||
nhacmp3youtube.com
|
||||
returnyoutubedislikeapi.com
|
||||
s.ytimg.com
|
||||
signaler-pa.youtube.com
|
||||
studio.youtube.com
|
||||
tv.youtube.com
|
||||
wide-youtube.l.google.com
|
||||
withyoutube.com
|
||||
youtu.be
|
||||
youtube.com
|
||||
youtube.googleapis.com
|
||||
youtubeeducation.com
|
||||
youtubeembeddedplayer.googleapis.com
|
||||
youtubefanfest.com
|
||||
youtubegaming.com
|
||||
youtubei.googleapis.com
|
||||
youtubekids.com
|
||||
youtubemobilesupport.com
|
||||
youtube-nocookie.com
|
||||
youtube-ui.l.google.com
|
||||
yt.be
|
||||
yt3.ggpht.com
|
||||
yt3.googleusercontent.com
|
||||
yt4.ggpht.com
|
||||
ytimg.com
|
||||
ytimg.l.google.com
|
||||
yting.com
|
||||
yt-video-upload.l.google.com
|
||||
youtube.ae
|
||||
youtube.al
|
||||
youtube.am
|
||||
youtube.at
|
||||
youtube.az
|
||||
youtube.ba
|
||||
youtube.be
|
||||
youtube.bg
|
||||
youtube.bh
|
||||
youtube.bo
|
||||
youtube.by
|
||||
youtube.ca
|
||||
youtube.cat
|
||||
youtube.ch
|
||||
youtube.cl
|
||||
youtube.co
|
||||
youtube.co.ae
|
||||
youtube.co.at
|
||||
youtube.co.cr
|
||||
youtube.co.hu
|
||||
youtube.co.id
|
||||
youtube.co.il
|
||||
youtube.co.in
|
||||
youtube.co.jp
|
||||
youtube.co.ke
|
||||
youtube.co.kr
|
||||
youtube.co.ma
|
||||
youtube.co.nz
|
||||
youtube.co.th
|
||||
youtube.co.tz
|
||||
youtube.co.ug
|
||||
youtube.co.uk
|
||||
youtube.co.ve
|
||||
youtube.co.za
|
||||
youtube.co.zw
|
||||
youtube.com.ar
|
||||
youtube.com.au
|
||||
youtube.com.az
|
||||
youtube.com.bd
|
||||
youtube.com.bh
|
||||
youtube.com.bo
|
||||
youtube.com.br
|
||||
youtube.com.by
|
||||
youtube.com.co
|
||||
youtube.com.do
|
||||
youtube.com.ec
|
||||
youtube.com.ee
|
||||
youtube.com.eg
|
||||
youtube.com.es
|
||||
youtube.com.gh
|
||||
youtube.com.gr
|
||||
youtube.com.gt
|
||||
youtube.com.hk
|
||||
youtube.com.hn
|
||||
youtube.com.hr
|
||||
youtube.com.jm
|
||||
youtube.com.jo
|
||||
youtube.com.kw
|
||||
youtube.com.lb
|
||||
youtube.com.lv
|
||||
youtube.com.ly
|
||||
youtube.com.mk
|
||||
youtube.com.mt
|
||||
youtube.com.mx
|
||||
youtube.com.my
|
||||
youtube.com.ng
|
||||
youtube.com.ni
|
||||
youtube.com.om
|
||||
youtube.com.pa
|
||||
youtube.com.pe
|
||||
youtube.com.ph
|
||||
youtube.com.pk
|
||||
youtube.com.pt
|
||||
youtube.com.py
|
||||
youtube.com.qa
|
||||
youtube.com.ro
|
||||
youtube.com.sa
|
||||
youtube.com.sg
|
||||
youtube.com.sv
|
||||
youtube.com.tn
|
||||
youtube.com.tr
|
||||
youtube.com.tw
|
||||
youtube.com.ua
|
||||
youtube.com.uy
|
||||
youtube.com.ve
|
||||
youtube.cr
|
||||
youtube.cz
|
||||
youtube.de
|
||||
youtube.dk
|
||||
youtube.ee
|
||||
youtube.es
|
||||
youtube.fi
|
||||
youtube.fr
|
||||
youtube.ge
|
||||
youtube.gr
|
||||
youtube.gt
|
||||
youtube.hk
|
||||
youtube.hr
|
||||
youtube.hu
|
||||
youtube.ie
|
||||
youtube.in
|
||||
youtube.iq
|
||||
youtube.is
|
||||
youtube.it
|
||||
youtube.jo
|
||||
youtube.jp
|
||||
youtube.kr
|
||||
youtube.kz
|
||||
youtube.la
|
||||
youtube.lk
|
||||
youtube.lt
|
||||
youtube.lu
|
||||
youtube.lv
|
||||
youtube.ly
|
||||
youtube.ma
|
||||
youtube.md
|
||||
youtube.me
|
||||
youtube.mk
|
||||
youtube.mn
|
||||
youtube.mx
|
||||
youtube.my
|
||||
youtube.ng
|
||||
youtube.ni
|
||||
youtube.nl
|
||||
youtube.no
|
||||
youtube.pa
|
||||
youtube.pe
|
||||
youtube.ph
|
||||
youtube.pk
|
||||
youtube.pl
|
||||
youtube.pr
|
||||
youtube.pt
|
||||
youtube.qa
|
||||
youtube.ro
|
||||
youtube.rs
|
||||
youtube.ru
|
||||
youtube.sa
|
||||
youtube.se
|
||||
youtube.sg
|
||||
youtube.si
|
||||
youtube.sk
|
||||
youtube.sn
|
||||
youtube.soy
|
||||
youtube.sv
|
||||
youtube.tn
|
||||
youtube.tv
|
||||
youtube.ua
|
||||
youtube.ug
|
||||
youtube.uy
|
||||
youtube.vn
|
||||
youtubego.co.id
|
||||
youtubego.co.in
|
||||
youtubego.com
|
||||
youtubego.com.br
|
||||
youtubego.id
|
||||
youtubego.in
|
||||
198
ansible/files/vyos/zapret/ipset/zapret-hosts-user.txt
Normal file
198
ansible/files/vyos/zapret/ipset/zapret-hosts-user.txt
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
cdn.youtube.com
|
||||
fonts.googleapis.com
|
||||
fonts.gstatic.com
|
||||
ggpht.com
|
||||
googleapis.com
|
||||
googleusercontent.com
|
||||
googlevideo.com
|
||||
i.ytimg.com
|
||||
i9.ytimg.com
|
||||
jnn-pa.googleapis.com
|
||||
kids.youtube.com
|
||||
m.youtube.com
|
||||
manifest.googlevideo.com
|
||||
music.youtube.com
|
||||
nhacmp3youtube.com
|
||||
returnyoutubedislikeapi.com
|
||||
s.ytimg.com
|
||||
signaler-pa.youtube.com
|
||||
studio.youtube.com
|
||||
tv.youtube.com
|
||||
wide-youtube.l.google.com
|
||||
withyoutube.com
|
||||
youtu.be
|
||||
youtube.com
|
||||
youtube.googleapis.com
|
||||
youtubeeducation.com
|
||||
youtubeembeddedplayer.googleapis.com
|
||||
youtubefanfest.com
|
||||
youtubegaming.com
|
||||
youtubei.googleapis.com
|
||||
youtubekids.com
|
||||
youtubemobilesupport.com
|
||||
youtube-nocookie.com
|
||||
youtube-ui.l.google.com
|
||||
yt.be
|
||||
yt3.ggpht.com
|
||||
yt3.googleusercontent.com
|
||||
yt4.ggpht.com
|
||||
ytimg.com
|
||||
ytimg.l.google.com
|
||||
yting.com
|
||||
yt-video-upload.l.google.com
|
||||
youtube.ae
|
||||
youtube.al
|
||||
youtube.am
|
||||
youtube.at
|
||||
youtube.az
|
||||
youtube.ba
|
||||
youtube.be
|
||||
youtube.bg
|
||||
youtube.bh
|
||||
youtube.bo
|
||||
youtube.by
|
||||
youtube.ca
|
||||
youtube.cat
|
||||
youtube.ch
|
||||
youtube.cl
|
||||
youtube.co
|
||||
youtube.co.ae
|
||||
youtube.co.at
|
||||
youtube.co.cr
|
||||
youtube.co.hu
|
||||
youtube.co.id
|
||||
youtube.co.il
|
||||
youtube.co.in
|
||||
youtube.co.jp
|
||||
youtube.co.ke
|
||||
youtube.co.kr
|
||||
youtube.co.ma
|
||||
youtube.co.nz
|
||||
youtube.co.th
|
||||
youtube.co.tz
|
||||
youtube.co.ug
|
||||
youtube.co.uk
|
||||
youtube.co.ve
|
||||
youtube.co.za
|
||||
youtube.co.zw
|
||||
youtube.com.ar
|
||||
youtube.com.au
|
||||
youtube.com.az
|
||||
youtube.com.bd
|
||||
youtube.com.bh
|
||||
youtube.com.bo
|
||||
youtube.com.br
|
||||
youtube.com.by
|
||||
youtube.com.co
|
||||
youtube.com.do
|
||||
youtube.com.ec
|
||||
youtube.com.ee
|
||||
youtube.com.eg
|
||||
youtube.com.es
|
||||
youtube.com.gh
|
||||
youtube.com.gr
|
||||
youtube.com.gt
|
||||
youtube.com.hk
|
||||
youtube.com.hn
|
||||
youtube.com.hr
|
||||
youtube.com.jm
|
||||
youtube.com.jo
|
||||
youtube.com.kw
|
||||
youtube.com.lb
|
||||
youtube.com.lv
|
||||
youtube.com.ly
|
||||
youtube.com.mk
|
||||
youtube.com.mt
|
||||
youtube.com.mx
|
||||
youtube.com.my
|
||||
youtube.com.ng
|
||||
youtube.com.ni
|
||||
youtube.com.om
|
||||
youtube.com.pa
|
||||
youtube.com.pe
|
||||
youtube.com.ph
|
||||
youtube.com.pk
|
||||
youtube.com.pt
|
||||
youtube.com.py
|
||||
youtube.com.qa
|
||||
youtube.com.ro
|
||||
youtube.com.sa
|
||||
youtube.com.sg
|
||||
youtube.com.sv
|
||||
youtube.com.tn
|
||||
youtube.com.tr
|
||||
youtube.com.tw
|
||||
youtube.com.ua
|
||||
youtube.com.uy
|
||||
youtube.com.ve
|
||||
youtube.cr
|
||||
youtube.cz
|
||||
youtube.de
|
||||
youtube.dk
|
||||
youtube.ee
|
||||
youtube.es
|
||||
youtube.fi
|
||||
youtube.fr
|
||||
youtube.ge
|
||||
youtube.gr
|
||||
youtube.gt
|
||||
youtube.hk
|
||||
youtube.hr
|
||||
youtube.hu
|
||||
youtube.ie
|
||||
youtube.in
|
||||
youtube.iq
|
||||
youtube.is
|
||||
youtube.it
|
||||
youtube.jo
|
||||
youtube.jp
|
||||
youtube.kr
|
||||
youtube.kz
|
||||
youtube.la
|
||||
youtube.lk
|
||||
youtube.lt
|
||||
youtube.lu
|
||||
youtube.lv
|
||||
youtube.ly
|
||||
youtube.ma
|
||||
youtube.md
|
||||
youtube.me
|
||||
youtube.mk
|
||||
youtube.mn
|
||||
youtube.mx
|
||||
youtube.my
|
||||
youtube.ng
|
||||
youtube.ni
|
||||
youtube.nl
|
||||
youtube.no
|
||||
youtube.pa
|
||||
youtube.pe
|
||||
youtube.ph
|
||||
youtube.pk
|
||||
youtube.pl
|
||||
youtube.pr
|
||||
youtube.pt
|
||||
youtube.qa
|
||||
youtube.ro
|
||||
youtube.rs
|
||||
youtube.ru
|
||||
youtube.sa
|
||||
youtube.se
|
||||
youtube.sg
|
||||
youtube.si
|
||||
youtube.sk
|
||||
youtube.sn
|
||||
youtube.soy
|
||||
youtube.sv
|
||||
youtube.tn
|
||||
youtube.tv
|
||||
youtube.ua
|
||||
youtube.ug
|
||||
youtube.uy
|
||||
youtube.vn
|
||||
youtubego.co.id
|
||||
youtubego.co.in
|
||||
youtubego.com
|
||||
youtubego.com.br
|
||||
youtubego.id
|
||||
youtubego.in
|
||||
10
ansible/files/vyos/zapret/ipset/zapret-ip-exclude.txt
Normal file
10
ansible/files/vyos/zapret/ipset/zapret-ip-exclude.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
127.0.0.0/8
|
||||
10.0.0.0/8
|
||||
172.16.0.0/12
|
||||
192.168.0.0/16
|
||||
169.254.0.0/16
|
||||
100.64.0.0/10
|
||||
::1
|
||||
fc00::/7
|
||||
fe80::/10
|
||||
153.76.194.24
|
||||
0
ansible/files/vyos/zapret/ipset/zapret-ip-user.txt
Normal file
0
ansible/files/vyos/zapret/ipset/zapret-ip-user.txt
Normal file
25
ansible/files/vyos/zapret/run.sh
Executable file
25
ansible/files/vyos/zapret/run.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# 1. Раскладываем дефолты (скрипты и блобы)
|
||||
[ -d /opt/zapret2/lua ] || cp -r /opt/zapret2/lua.dist /opt/zapret2/lua
|
||||
[ -d /opt/zapret2/files/fake ] || cp -r /opt/zapret2/files/fake.dist /opt/zapret2/files/fake
|
||||
|
||||
# 2. Подкладываем конфиг и списки хостов
|
||||
cp -f /etc/zapret/config /opt/zapret2/config
|
||||
mkdir -p /opt/zapret2/ipset
|
||||
cp -rf /etc/zapret/ipset/* /opt/zapret2/ipset/ 2>/dev/null || true
|
||||
|
||||
# 3. Стартуем родной zapret2 (он сам настроит nftables и поднимет nfqws2)
|
||||
/opt/zapret2/init.d/sysv/zapret2 start
|
||||
|
||||
# 4. Обработка остановки контейнера
|
||||
cleanup() {
|
||||
/opt/zapret2/init.d/sysv/zapret2 stop || true
|
||||
exit 0
|
||||
}
|
||||
trap cleanup TERM INT EXIT
|
||||
|
||||
# Держим контейнер в фоне
|
||||
sleep infinity &
|
||||
wait $!
|
||||
34
ansible/inventory.yml
Normal file
34
ansible/inventory.yml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
all:
|
||||
children:
|
||||
hypervisors:
|
||||
hosts:
|
||||
pve0:
|
||||
ansible_host: 192.168.1.177
|
||||
ansible_user: root
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
|
||||
routers:
|
||||
hosts:
|
||||
vyos_router:
|
||||
ansible_host: 192.168.1.2
|
||||
ansible_user: vyos
|
||||
ansible_network_os: vyos.vyos.vyos
|
||||
ansible_connection: network_cli
|
||||
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
||||
ansible_paramiko_host_key_auto_add: true
|
||||
|
||||
tier0_lxc:
|
||||
hosts:
|
||||
dns0:
|
||||
ansible_host: 10.0.10.11
|
||||
vault0:
|
||||
ansible_host: 10.0.10.12
|
||||
git0:
|
||||
ansible_host: 10.0.10.13
|
||||
storage0:
|
||||
ansible_host: 10.0.10.14
|
||||
registry0:
|
||||
ansible_host: 10.0.10.15
|
||||
vars:
|
||||
ansible_user: root
|
||||
ansible_ssh_common_args: '-J vyos@192.168.1.2'
|
||||
143
ansible/playbooks/01_pve_host_day0.yml
Normal file
143
ansible/playbooks/01_pve_host_day0.yml
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
---
|
||||
- name: Configure Proxmox Host Day-0 Integration
|
||||
hosts: pve0
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Ensure nfsd kernel module is loaded on PVE host
|
||||
ansible.builtin.command: modprobe nfsd
|
||||
changed_when: false
|
||||
|
||||
- name: Persist nfsd module in /etc/modules
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/modules
|
||||
line: "nfsd"
|
||||
state: present
|
||||
|
||||
- name: Ensure host ZFS directories exist with 0777 permissions
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "0"
|
||||
group: "0"
|
||||
mode: "0777"
|
||||
loop:
|
||||
- /terra/media
|
||||
- /terra/torrents
|
||||
- /terra/vault
|
||||
- /terra/registry
|
||||
- /terra/models
|
||||
|
||||
# ================= LXC 104 (storage0 - NAS) =================
|
||||
- name: Check existing mount points for LXC 104
|
||||
ansible.builtin.command: >
|
||||
grep -q "^{{ item.id }}: {{ item.src }},mp={{ item.dest }}" /etc/pve/lxc/104.conf
|
||||
register: check_104
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
loop:
|
||||
- { id: 'mp0', src: '/terra/media', dest: '/media' }
|
||||
- { id: 'mp1', src: '/terra/torrents', dest: '/torrents' }
|
||||
- { id: 'mp2', src: '/terra/vault', dest: '/backups' }
|
||||
- { id: 'mp3', src: '/terra/models', dest: '/models' }
|
||||
|
||||
- name: Apply mount points for LXC 104
|
||||
ansible.builtin.command: pct set 104 -{{ item.item.id }} {{ item.item.src }},mp={{ item.item.dest }}
|
||||
when: item.rc != 0
|
||||
register: apply_104
|
||||
loop: "{{ check_104.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.id }}"
|
||||
|
||||
- name: Configure AppArmor unconfined for LXC 104 kernel NFS
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/pve/lxc/104.conf
|
||||
line: "lxc.apparmor.profile: unconfined"
|
||||
state: present
|
||||
register: apparmor_104
|
||||
|
||||
- name: Reboot LXC 104 to apply mounts and AppArmor
|
||||
ansible.builtin.command: pct reboot 104
|
||||
when: apply_104.changed or apparmor_104.changed
|
||||
|
||||
# ================= LXC 105 (registry0 - Zot OCI) =================
|
||||
- name: Check existing mount points for LXC 105
|
||||
ansible.builtin.command: >
|
||||
grep -q "^{{ item.id }}: {{ item.src }},mp={{ item.dest }}" /etc/pve/lxc/105.conf
|
||||
register: check_105
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
loop:
|
||||
- { id: 'mp0', src: '/terra/registry', dest: '/mnt/registry' }
|
||||
|
||||
- name: Apply mount points for LXC 105
|
||||
ansible.builtin.command: pct set 105 -{{ item.item.id }} {{ item.item.src }},mp={{ item.item.dest }}
|
||||
when: item.rc != 0
|
||||
register: apply_105
|
||||
loop: "{{ check_105.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.id }}"
|
||||
|
||||
- name: Reboot LXC 105 to apply pending mount points
|
||||
ansible.builtin.command: pct reboot 105
|
||||
when: apply_105.changed
|
||||
|
||||
# ================= DAY-0 OS IMAGES & TEMPLATES (SSOT) =================
|
||||
- name: Update pveam repository catalog
|
||||
ansible.builtin.command: pveam update
|
||||
changed_when: false
|
||||
|
||||
- name: Query latest Debian 12 standard template name
|
||||
ansible.builtin.shell: pveam available --section system | awk '/debian-12-standard/ {print $2}' | tail -n 1
|
||||
register: pve_debian_tmpl
|
||||
changed_when: false
|
||||
|
||||
- name: Ensure Debian 12 template is downloaded and symlinked
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
CACHE_DIR="/var/lib/vz/template/cache"
|
||||
TARGET_LINK="${CACHE_DIR}/debian-12-standard_amd64.tar.zst"
|
||||
if [ ! -f "${TARGET_LINK}" ]; then
|
||||
ACTUAL_FILE=$(ls -1 ${CACHE_DIR}/debian-12-standard_*_amd64.tar.zst 2>/dev/null | tail -n 1 || true)
|
||||
if [ -z "${ACTUAL_FILE}" ]; then
|
||||
pveam download local {{ pve_debian_tmpl.stdout }}
|
||||
ACTUAL_FILE="${CACHE_DIR}/{{ pve_debian_tmpl.stdout }}"
|
||||
fi
|
||||
ln -sf "${ACTUAL_FILE}" "${TARGET_LINK}"
|
||||
echo "DOWNLOADED"
|
||||
fi
|
||||
register: debian_download_status
|
||||
changed_when: "'DOWNLOADED' in debian_download_status.stdout"
|
||||
|
||||
- name: Query latest Alpine template name
|
||||
ansible.builtin.shell: pveam available --section system | awk '/alpine-3\.[0-9]+-default/ {print $2}' | tail -n 1
|
||||
register: pve_alpine_tmpl
|
||||
changed_when: false
|
||||
|
||||
- name: Ensure Alpine 3.24 template is downloaded and symlinked
|
||||
ansible.builtin.shell: |
|
||||
set -e
|
||||
CACHE_DIR="/var/lib/vz/template/cache"
|
||||
TARGET_LINK="${CACHE_DIR}/alpine-3.24-default_20260714_amd64.tar.xz"
|
||||
if [ ! -f "${TARGET_LINK}" ]; then
|
||||
ACTUAL_FILE=$(ls -1 ${CACHE_DIR}/alpine-*-default_*_amd64.tar.xz 2>/dev/null | tail -n 1 || true)
|
||||
if [ -z "${ACTUAL_FILE}" ]; then
|
||||
pveam download local {{ pve_alpine_tmpl.stdout }}
|
||||
ACTUAL_FILE="${CACHE_DIR}/{{ pve_alpine_tmpl.stdout }}"
|
||||
fi
|
||||
ln -sf "${ACTUAL_FILE}" "${TARGET_LINK}"
|
||||
echo "DOWNLOADED"
|
||||
fi
|
||||
register: alpine_download_status
|
||||
changed_when: "'DOWNLOADED' in alpine_download_status.stdout"
|
||||
|
||||
- name: Check if Talos Linux ISO exists
|
||||
ansible.builtin.stat:
|
||||
path: /var/lib/vz/template/iso/talos-amd64.iso
|
||||
register: talos_iso
|
||||
|
||||
- name: Ensure Talos Linux ISO (v1.14.0) is present
|
||||
ansible.builtin.get_url:
|
||||
url: https://github.com/siderolabs/talos/releases/download/v1.14.0/metal-amd64.iso
|
||||
dest: /var/lib/vz/template/iso/talos-amd64.iso
|
||||
mode: "0644"
|
||||
when: not talos_iso.stat.exists
|
||||
173
ansible/playbooks/02_vyos_network_day0.yml
Normal file
173
ansible/playbooks/02_vyos_network_day0.yml
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
---
|
||||
- name: Configure VyOS Network and Sing-Box
|
||||
hosts: vyos_router
|
||||
gather_facts: false
|
||||
tasks:
|
||||
# --- 1. ДОСТАВКА КОНФИГА ЧЕРЕЗ NATIVE SSH ---
|
||||
- name: Ensure sing-box directory exists
|
||||
ansible.builtin.file:
|
||||
path: /config/sing-box
|
||||
state: directory
|
||||
owner: vyos
|
||||
group: vyattacfg
|
||||
mode: "0755"
|
||||
vars:
|
||||
ansible_connection: ssh
|
||||
become: true
|
||||
|
||||
- name: Deploy sing-box config via native copy
|
||||
ansible.builtin.copy:
|
||||
src: "{{ playbook_dir }}/../files/vyos/sing-box/config.json"
|
||||
dest: "/config/sing-box/config.json"
|
||||
owner: vyos
|
||||
group: vyattacfg
|
||||
mode: "0644"
|
||||
vars:
|
||||
ansible_connection: ssh
|
||||
become: true
|
||||
|
||||
- name: Persist route_localnet for DNS DNAT
|
||||
ansible.posix.sysctl:
|
||||
name: "{{ item }}"
|
||||
value: "1"
|
||||
state: present
|
||||
sysctl_file: /etc/sysctl.d/99-singbox.conf
|
||||
reload: true
|
||||
loop:
|
||||
- net.ipv4.conf.all.route_localnet
|
||||
- net.ipv4.conf.eth0.route_localnet
|
||||
- net.ipv4.conf.eth3.route_localnet
|
||||
vars:
|
||||
ansible_connection: ssh
|
||||
become: true
|
||||
- name: Ensure zapret directory exists
|
||||
ansible.builtin.file:
|
||||
path: /config/zapret
|
||||
state: directory
|
||||
owner: vyos
|
||||
group: vyattacfg
|
||||
mode: "0755"
|
||||
vars:
|
||||
ansible_connection: ssh
|
||||
become: true
|
||||
|
||||
- name: Deploy zapret directory via native copy
|
||||
ansible.builtin.copy:
|
||||
src: "{{ playbook_dir }}/../files/vyos/zapret/"
|
||||
dest: "/config/zapret/"
|
||||
owner: vyos
|
||||
group: vyattacfg
|
||||
mode: "0755"
|
||||
vars:
|
||||
ansible_connection: ssh
|
||||
become: true
|
||||
|
||||
# --- 2. PULL ОБРАЗА (OP-MODE) ---
|
||||
- name: Check existing container images
|
||||
vyos.vyos.vyos_command:
|
||||
commands:
|
||||
- show container image
|
||||
register: vyos_images
|
||||
|
||||
- name: Pull sing-box image if not present (Op Mode)
|
||||
vyos.vyos.vyos_command:
|
||||
commands:
|
||||
- add container image ghcr.io/sagernet/sing-box:latest
|
||||
when: "'sing-box' not in vyos_images.stdout[0]"
|
||||
|
||||
# --- 3. СЕТЬ, DNAT И КОНТЕЙНЕР (CONFIG MODE) ---
|
||||
- name: Apply base network, DNS DNAT, and sing-box container
|
||||
vyos.vyos.vyos_config:
|
||||
lines:
|
||||
- set interfaces ethernet eth0 address '192.168.1.2/24'
|
||||
- set interfaces ethernet eth0 description 'WAN_TRUNK'
|
||||
- set interfaces ethernet eth2 address '10.0.10.1/24'
|
||||
- set interfaces ethernet eth2 description 'TIER0'
|
||||
- set interfaces ethernet eth1 address '10.0.20.1/24'
|
||||
- set interfaces ethernet eth1 description 'K8S'
|
||||
- set interfaces ethernet eth3 address '10.0.30.1/24'
|
||||
- set interfaces ethernet eth3 description 'LAN_CLIENTS'
|
||||
- set interfaces wireguard wg0 address '10.8.0.2/24'
|
||||
- set interfaces wireguard wg0 description 'TUNNEL_TO_VPS_FIN21'
|
||||
- set interfaces wireguard wg0 private-key 'mP869Eu59vE0hlvFHoGjgKT+j6UZgxIYuojZCbGWjVo='
|
||||
- set interfaces wireguard wg0 peer fin21 address '153.76.194.24'
|
||||
- set interfaces wireguard wg0 peer fin21 port '51820'
|
||||
- set interfaces wireguard wg0 peer fin21 public-key 'tS0m/x/dVCs8+N+mtSH3PENWpEUymJDiuPNWrCySMWY='
|
||||
- set interfaces wireguard wg0 peer fin21 allowed-ips '10.8.0.0/24'
|
||||
- set interfaces wireguard wg0 peer fin21 persistent-keepalive '25'
|
||||
- set protocols static route 0.0.0.0/0 next-hop 192.168.1.1
|
||||
- set nat source rule 100 outbound-interface name 'eth0'
|
||||
- set nat source rule 100 source address '0.0.0.0/0'
|
||||
- set nat source rule 100 translation address 'masquerade'
|
||||
- set nat source rule 110 description 'NAT_WG0_TO_LAN'
|
||||
- set nat source rule 110 outbound-interface name 'eth3'
|
||||
- set nat source rule 110 source address '10.8.0.0/24'
|
||||
- set nat source rule 110 translation address 'masquerade'
|
||||
# DNAT перехват DNS на Sing-Box
|
||||
- set firewall group interface-group LAN interface 'eth0'
|
||||
- set firewall group interface-group LAN interface 'eth3'
|
||||
- set nat destination rule 53 description 'REDIRECT_DNS_TO_SINGBOX'
|
||||
- set nat destination rule 53 destination port '53'
|
||||
- set nat destination rule 53 inbound-interface group 'LAN'
|
||||
- set nat destination rule 53 protocol 'tcp_udp'
|
||||
- set nat destination rule 53 translation address '127.0.0.42'
|
||||
- set nat destination rule 53 translation port '53'
|
||||
# Железный фаервол изоляции wg0 (периметр VPS)
|
||||
# 1. Транзитный трафик (Forward): разрешаем ТОЛЬКО 10.0.30.200:80,443, остальное дропаем
|
||||
- set firewall ipv4 forward filter rule 10 action 'accept'
|
||||
- set firewall ipv4 forward filter rule 10 state established
|
||||
- set firewall ipv4 forward filter rule 10 state related
|
||||
- set firewall ipv4 forward filter rule 20 action 'accept'
|
||||
- set firewall ipv4 forward filter rule 20 inbound-interface name 'wg0'
|
||||
- set firewall ipv4 forward filter rule 20 destination address '10.0.30.200'
|
||||
- set firewall ipv4 forward filter rule 20 destination port '80,443'
|
||||
- set firewall ipv4 forward filter rule 20 protocol 'tcp'
|
||||
- set firewall ipv4 forward filter rule 30 action 'drop'
|
||||
- set firewall ipv4 forward filter rule 30 inbound-interface name 'wg0'
|
||||
|
||||
# 2. Трафик к самому роутеру (Input): запрещаем дедику доступ к сокетам VyOS (SSH и т.д.)
|
||||
- set firewall ipv4 input filter rule 10 action 'accept'
|
||||
- set firewall ipv4 input filter rule 10 state established
|
||||
- set firewall ipv4 input filter rule 10 state related
|
||||
- set firewall ipv4 input filter rule 20 action 'drop'
|
||||
- set firewall ipv4 input filter rule 20 inbound-interface name 'wg0'
|
||||
# DHCP
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 subnet-id '20'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 option default-router '10.0.20.1'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 option name-server '10.0.10.11'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 range 0 start '10.0.20.100'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 range 0 stop '10.0.20.150'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 static-mapping talos-master-1 ip-address '10.0.20.10'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 static-mapping talos-master-1 mac 'bc:24:11:71:b6:82'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 static-mapping talos-worker-1 ip-address '10.0.20.11'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 static-mapping talos-worker-1 mac 'bc:24:11:12:c5:1b'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 static-mapping talos-worker-2 ip-address '10.0.20.12'
|
||||
- set service dhcp-server shared-network-name K8S subnet 10.0.20.0/24 static-mapping talos-worker-2 mac 'bc:24:11:ef:1a:d4'
|
||||
- set service dhcp-server shared-network-name LAN_CLIENTS subnet 10.0.30.0/24 subnet-id '30'
|
||||
- set service dhcp-server shared-network-name LAN_CLIENTS subnet 10.0.30.0/24 option default-router '10.0.30.1'
|
||||
- set service dhcp-server shared-network-name LAN_CLIENTS subnet 10.0.30.0/24 option name-server '10.0.10.11'
|
||||
- set service dhcp-server shared-network-name LAN_CLIENTS subnet 10.0.30.0/24 range 0 start '10.0.30.100'
|
||||
- set service dhcp-server shared-network-name LAN_CLIENTS subnet 10.0.30.0/24 range 0 stop '10.0.30.150'
|
||||
# Контейнер Sing-Box
|
||||
- set container name sing-box image 'ghcr.io/sagernet/sing-box:latest'
|
||||
- set container name sing-box allow-host-networks
|
||||
- set container name sing-box capability 'net-admin'
|
||||
- set container name sing-box capability 'net-raw'
|
||||
- set container name sing-box restart 'always'
|
||||
- set container name sing-box memory '256'
|
||||
- set container name sing-box command 'run'
|
||||
- set container name sing-box arguments '-c /etc/sing-box/config.json'
|
||||
- set container name sing-box volume singbox-cfg destination '/etc/sing-box'
|
||||
- set container name sing-box volume singbox-cfg source '/config/sing-box'
|
||||
# Контейнер Zapret2
|
||||
- set container name zapret2 image 'docker.io/vernette/ss-zapret2:latest'
|
||||
- set container name zapret2 allow-host-networks
|
||||
- set container name zapret2 capability 'net-admin'
|
||||
- set container name zapret2 capability 'net-raw'
|
||||
- set container name zapret2 restart 'always'
|
||||
- set container name zapret2 memory '256'
|
||||
- set container name zapret2 entrypoint '/bin/sh'
|
||||
- set container name zapret2 command '/etc/zapret/run.sh'
|
||||
- set container name zapret2 volume zapret-cfg destination '/etc/zapret'
|
||||
- set container name zapret2 volume zapret-cfg source '/config/zapret'
|
||||
save: true
|
||||
132
ansible/playbooks/03_zot_registry.yml
Normal file
132
ansible/playbooks/03_zot_registry.yml
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
---
|
||||
- name: Deploy Zot OCI Registry
|
||||
hosts: registry0
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Create zot group
|
||||
ansible.builtin.group:
|
||||
name: zot
|
||||
state: present
|
||||
- name: Create zot user
|
||||
ansible.builtin.user:
|
||||
name: zot
|
||||
group: zot
|
||||
system: true
|
||||
create_home: false
|
||||
shell: /usr/sbin/nologin
|
||||
state: present
|
||||
- name: Ensure Zot configuration directory exists
|
||||
ansible.builtin.file:
|
||||
path: /etc/zot
|
||||
state: directory
|
||||
owner: zot
|
||||
group: zot
|
||||
mode: "0755"
|
||||
- name: Download Zot binary
|
||||
ansible.builtin.get_url:
|
||||
url: https://github.com/project-zot/zot/releases/download/v2.1.1/zot-linux-amd64
|
||||
dest: /usr/local/bin/zot
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
notify: Restart Zot
|
||||
- name: Generate Zot configuration
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/zot/config.json
|
||||
owner: zot
|
||||
group: zot
|
||||
mode: "0644"
|
||||
content: |
|
||||
{
|
||||
"distSpecVersion": "1.1.0-dev",
|
||||
"storage": {
|
||||
"rootDirectory": "/mnt/registry",
|
||||
"gc": true
|
||||
},
|
||||
"http": {
|
||||
"address": "0.0.0.0",
|
||||
"port": "5000"
|
||||
},
|
||||
"extensions": {
|
||||
"search": {
|
||||
"enable": true
|
||||
},
|
||||
"ui": {
|
||||
"enable": true
|
||||
},
|
||||
"sync": {
|
||||
"enable": true,
|
||||
"registries": [
|
||||
{
|
||||
"urls": ["https://registry-1.docker.io"],
|
||||
"onDemand": true,
|
||||
"tlsVerify": true,
|
||||
"content": [
|
||||
{
|
||||
"prefix": "**",
|
||||
"destination": "/docker.io"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"urls": ["https://ghcr.io"],
|
||||
"onDemand": true,
|
||||
"tlsVerify": true,
|
||||
"content": [
|
||||
{
|
||||
"prefix": "**",
|
||||
"destination": "/ghcr.io"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"urls": ["https://registry.k8s.io"],
|
||||
"onDemand": true,
|
||||
"tlsVerify": true,
|
||||
"content": [
|
||||
{
|
||||
"prefix": "**",
|
||||
"destination": "/k8s.io"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"urls": ["https://quay.io"],
|
||||
"onDemand": true,
|
||||
"tlsVerify": true,
|
||||
"content": [{"prefix": "**", "destination": "/quay.io"}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
notify: Restart Zot
|
||||
- name: Create Zot systemd service
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/systemd/system/zot.service
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Zot OCI Registry
|
||||
After=network.target
|
||||
[Service]
|
||||
User=zot
|
||||
Group=zot
|
||||
ExecStart=/usr/local/bin/zot serve /etc/zot/config.json
|
||||
Restart=always
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
notify: Restart Zot
|
||||
- name: Enable and start Zot service
|
||||
ansible.builtin.systemd:
|
||||
name: zot
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
handlers:
|
||||
- name: Restart Zot
|
||||
ansible.builtin.systemd:
|
||||
name: zot
|
||||
state: restarted
|
||||
132
ansible/playbooks/04_technitium_dns.yml
Normal file
132
ansible/playbooks/04_technitium_dns.yml
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
---
|
||||
- name: Deploy and Configure Technitium DNS on Debian 12
|
||||
hosts: dns0
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Update APT cache and install dependencies
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- curl
|
||||
- tar
|
||||
- libicu72
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Download dotnet-install script
|
||||
ansible.builtin.get_url:
|
||||
url: https://dot.net/v1/dotnet-install.sh
|
||||
dest: /tmp/dotnet-install.sh
|
||||
mode: "0755"
|
||||
|
||||
- name: Install .NET 10 Runtime
|
||||
ansible.builtin.command:
|
||||
cmd: /tmp/dotnet-install.sh --runtime aspnetcore --channel 10.0 --install-dir /usr/share/dotnet
|
||||
creates: /usr/share/dotnet/shared/Microsoft.NETCore.App/10.0.*
|
||||
|
||||
- name: Create dotnet symlink
|
||||
ansible.builtin.file:
|
||||
src: /usr/share/dotnet/dotnet
|
||||
dest: /usr/bin/dotnet
|
||||
state: link
|
||||
|
||||
- name: Ensure Technitium DNS directory exists
|
||||
ansible.builtin.file:
|
||||
path: /opt/technitium/dns
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Download and extract Technitium DNS
|
||||
ansible.builtin.unarchive:
|
||||
src: https://download.technitium.com/dns/DnsServerPortable.tar.gz
|
||||
dest: /opt/technitium/dns
|
||||
remote_src: true
|
||||
notify: Restart Technitium
|
||||
|
||||
- name: Create systemd service
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/systemd/system/technitium-dns.service
|
||||
mode: "0644"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Technitium DNS Server
|
||||
After=network.target
|
||||
[Service]
|
||||
ExecStart=/usr/bin/dotnet /opt/technitium/dns/DnsServerApp.dll
|
||||
WorkingDirectory=/opt/technitium/dns
|
||||
Restart=always
|
||||
SyslogIdentifier=technitium-dns
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
notify: Restart Technitium
|
||||
|
||||
- name: Enable and start Technitium DNS service
|
||||
ansible.builtin.systemd:
|
||||
name: technitium-dns
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
|
||||
- name: Wait for Technitium HTTP API port 5380 to become available
|
||||
ansible.builtin.wait_for:
|
||||
port: 5380
|
||||
host: 127.0.0.1
|
||||
state: started
|
||||
timeout: 20
|
||||
|
||||
# ================= ДЕКЛАРАТИВНЫЕ ЗОНЫ И ЗАПИСИ (SSOT) =================
|
||||
- name: Authenticate with Technitium API to get session token
|
||||
ansible.builtin.uri:
|
||||
url: "http://127.0.0.1:5380/api/user/login?user=admin&pass={{ lookup('env', 'TECHNITIUM_PASSWORD') | default('admin', true) }}"
|
||||
method: GET
|
||||
status_code: [200]
|
||||
register: dns_auth
|
||||
failed_when: dns_auth.json.status != 'ok'
|
||||
|
||||
- name: Apply Technitium server settings from JSON manifest
|
||||
ansible.builtin.uri:
|
||||
url: "http://127.0.0.1:5380/api/settings/set?token={{ dns_auth.json.token }}"
|
||||
method: POST
|
||||
body_format: json
|
||||
body: "{{ lookup('file', playbook_dir + '/../files/technitium/settings.json') }}"
|
||||
status_code: [200]
|
||||
register: settings_res
|
||||
failed_when: settings_res.json.status != 'ok'
|
||||
|
||||
- name: Check installed DNS apps
|
||||
ansible.builtin.uri:
|
||||
url: "http://127.0.0.1:5380/api/apps/list?token={{ dns_auth.json.token }}"
|
||||
method: GET
|
||||
status_code: [200]
|
||||
register: installed_apps
|
||||
|
||||
- name: Download and install Query Logs (Sqlite) from store
|
||||
ansible.builtin.uri:
|
||||
url: "http://127.0.0.1:5380/api/apps/downloadAndInstall?token={{ dns_auth.json.token }}&name=Query%20Logs%20(Sqlite)&url=https://download.technitium.com/dns/apps/QueryLogsSqliteApp-v9.1.zip"
|
||||
timeout: 120
|
||||
method: GET
|
||||
status_code: [200]
|
||||
when: "'Query Logs (Sqlite)' not in (installed_apps.json.response.apps | default([]) | map(attribute='name') | list)"
|
||||
|
||||
- name: Ensure authoritative zone svo88.space exists
|
||||
ansible.builtin.uri:
|
||||
url: "http://127.0.0.1:5380/api/zones/create?token={{ dns_auth.json.token }}&zone=svo88.space&type=Primary"
|
||||
method: GET
|
||||
status_code: [200]
|
||||
register: zone_create
|
||||
failed_when: zone_create.json.status != 'ok' and 'already exists' not in zone_create.json.errorMessage | default('')
|
||||
|
||||
- name: Ensure wildcard A-record *.svo88.space points to Traefik VIP (10.0.30.200)
|
||||
ansible.builtin.uri:
|
||||
url: "http://127.0.0.1:5380/api/zones/records/add?token={{ dns_auth.json.token }}&zone=svo88.space&domain=*.svo88.space&type=A&ipAddress=10.0.30.200&overwrite=true"
|
||||
method: GET
|
||||
status_code: [200]
|
||||
register: record_create
|
||||
failed_when: record_create.json.status != 'ok'
|
||||
|
||||
|
||||
|
||||
handlers:
|
||||
- name: Restart Technitium
|
||||
ansible.builtin.systemd:
|
||||
name: technitium-dns
|
||||
state: restarted
|
||||
102
ansible/playbooks/05_openbao_vault.yml
Normal file
102
ansible/playbooks/05_openbao_vault.yml
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
- name: Deploy OpenBao Vault
|
||||
hosts: vault0
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Update APT cache and install dependencies
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- curl
|
||||
- gpg
|
||||
- apt-transport-https
|
||||
- unzip
|
||||
state: present
|
||||
update_cache: true
|
||||
- name: Create bao group
|
||||
ansible.builtin.group:
|
||||
name: bao
|
||||
state: present
|
||||
- name: Create bao user
|
||||
ansible.builtin.user:
|
||||
name: bao
|
||||
group: bao
|
||||
system: true
|
||||
create_home: false
|
||||
shell: /usr/sbin/nologin
|
||||
state: present
|
||||
- name: Ensure bao configuration directory exists
|
||||
ansible.builtin.file:
|
||||
path: /etc/bao
|
||||
state: directory
|
||||
owner: bao
|
||||
group: bao
|
||||
mode: "0755"
|
||||
- name: Ensure bao data directory exists
|
||||
ansible.builtin.file:
|
||||
path: /var/lib/bao/data
|
||||
state: directory
|
||||
owner: bao
|
||||
group: bao
|
||||
mode: "0750"
|
||||
- name: Download and extract OpenBao binary
|
||||
ansible.builtin.unarchive:
|
||||
src: https://github.com/openbao/openbao/releases/download/v2.0.1/bao_2.0.1_Linux_x86_64.tar.gz
|
||||
dest: /usr/local/bin
|
||||
remote_src: true
|
||||
creates: /usr/local/bin/bao
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
notify: Restart OpenBao
|
||||
- name: Generate OpenBao configuration
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/bao/vault.hcl
|
||||
owner: bao
|
||||
group: bao
|
||||
mode: "0644"
|
||||
content: |
|
||||
disable_mlock = true
|
||||
ui = true
|
||||
storage "file" {
|
||||
path = "/var/lib/bao/data"
|
||||
}
|
||||
listener "tcp" {
|
||||
address = "0.0.0.0:8200"
|
||||
tls_disable = 1
|
||||
}
|
||||
notify: Restart OpenBao
|
||||
- name: Create OpenBao systemd service
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/systemd/system/openbao.service
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=OpenBao Secrets Management
|
||||
After=network.target
|
||||
[Service]
|
||||
User=bao
|
||||
Group=bao
|
||||
ExecStart=/usr/local/bin/bao server -config=/etc/bao/vault.hcl
|
||||
Restart=on-failure
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
notify: Restart OpenBao
|
||||
- name: Enable and start OpenBao service
|
||||
ansible.builtin.systemd:
|
||||
name: openbao
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
- name: Wait for OpenBao port 8200 to become available
|
||||
ansible.builtin.wait_for:
|
||||
port: 8200
|
||||
host: 127.0.0.1
|
||||
state: started
|
||||
timeout: 30
|
||||
handlers:
|
||||
- name: Restart OpenBao
|
||||
ansible.builtin.systemd:
|
||||
name: openbao
|
||||
state: restarted
|
||||
131
ansible/playbooks/06_forgejo_git.yml
Normal file
131
ansible/playbooks/06_forgejo_git.yml
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
---
|
||||
- name: Deploy Forgejo GitOps Server
|
||||
hosts: git0
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Update APT cache and install dependencies
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- git
|
||||
- curl
|
||||
state: present
|
||||
update_cache: true
|
||||
- name: Create git group
|
||||
ansible.builtin.group:
|
||||
name: git
|
||||
state: present
|
||||
- name: Create git user
|
||||
ansible.builtin.user:
|
||||
name: git
|
||||
group: git
|
||||
system: true
|
||||
home: /var/lib/forgejo
|
||||
shell: /bin/bash
|
||||
state: present
|
||||
- name: Ensure Forgejo directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: git
|
||||
group: git
|
||||
mode: "0750"
|
||||
loop:
|
||||
- /etc/forgejo
|
||||
- /var/lib/forgejo
|
||||
- /var/lib/forgejo/data
|
||||
- /var/lib/forgejo/custom
|
||||
- /var/lib/forgejo/log
|
||||
- name: Check if Forgejo binary exists
|
||||
ansible.builtin.stat:
|
||||
path: /usr/local/bin/forgejo
|
||||
register: forgejo_bin
|
||||
- name: Download Forgejo binary
|
||||
ansible.builtin.get_url:
|
||||
url: https://codeberg.org/forgejo/forgejo/releases/download/v7.0.4/forgejo-7.0.4-linux-amd64
|
||||
dest: /usr/local/bin/forgejo
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
timeout: 30
|
||||
when: not forgejo_bin.stat.exists or forgejo_bin.stat.size == 0
|
||||
notify: Restart Forgejo
|
||||
- name: Generate Forgejo configuration
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/forgejo/app.ini
|
||||
owner: git
|
||||
group: git
|
||||
mode: "0640"
|
||||
content: |
|
||||
APP_NAME = Sovereign C2 GitOps
|
||||
RUN_USER = git
|
||||
WORK_PATH = /var/lib/forgejo
|
||||
[database]
|
||||
DB_TYPE = sqlite3
|
||||
PATH = /var/lib/forgejo/data/forgejo.db
|
||||
[server]
|
||||
DOMAIN = git.svo88.space
|
||||
ROOT_URL = https://git.svo88.space/
|
||||
HTTP_PORT = 3000
|
||||
SSH_PORT = 2222
|
||||
DISABLE_SSH = false
|
||||
START_SSH_SERVER = true
|
||||
[service]
|
||||
DISABLE_REGISTRATION = true
|
||||
REQUIRE_SIGNIN_VIEW = false'
|
||||
[oauth2_client]
|
||||
ENABLE_AUTO_REGISTRATION = true
|
||||
[repository]
|
||||
ENABLE_PUSH_CREATE_USER = true
|
||||
ENABLE_PUSH_CREATE_ORG = true
|
||||
DEFAULT_PUSH_CREATE_PRIVATE = false
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
notify: Restart Forgejo
|
||||
- name: Create Forgejo systemd service
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/systemd/system/forgejo.service
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Forgejo Git Service
|
||||
After=network.target
|
||||
[Service]
|
||||
Type=simple
|
||||
User=git
|
||||
Group=git
|
||||
WorkingDirectory=/var/lib/forgejo
|
||||
ExecStart=/usr/local/bin/forgejo web -c /etc/forgejo/app.ini
|
||||
Restart=always
|
||||
Environment=USER=git HOME=/var/lib/forgejo GITEA_WORK_DIR=/var/lib/forgejo
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
notify: Restart Forgejo
|
||||
- name: Enable and start Forgejo service
|
||||
ansible.builtin.systemd:
|
||||
name: forgejo
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
- name: Wait for Forgejo port 3000 to become available
|
||||
ansible.builtin.wait_for:
|
||||
port: 3000
|
||||
host: 127.0.0.1
|
||||
state: started
|
||||
timeout: 30
|
||||
- name: Initialize Forgejo database schema
|
||||
ansible.builtin.command: >
|
||||
su - git -c "/usr/local/bin/forgejo --work-path /var/lib/forgejo --config /etc/forgejo/app.ini migrate"
|
||||
changed_when: false
|
||||
- name: Create initial admin user
|
||||
ansible.builtin.command: >
|
||||
su - git -c "/usr/local/bin/forgejo --work-path /var/lib/forgejo --config /etc/forgejo/app.ini admin user create --admin --username atlas --password 'AtlasAdmin2026!' --email atlas@c2 --must-change-password=false"
|
||||
register: admin_user_res
|
||||
failed_when: admin_user_res.rc != 0 and 'already exists' not in admin_user_res.stderr and 'already exists' not in admin_user_res.stdout
|
||||
changed_when: admin_user_res.rc == 0
|
||||
handlers:
|
||||
- name: Restart Forgejo
|
||||
ansible.builtin.systemd:
|
||||
name: forgejo
|
||||
state: restarted
|
||||
71
ansible/playbooks/07_nas_storage.yml
Normal file
71
ansible/playbooks/07_nas_storage.yml
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
- name: Deploy NAS Storage on Alpine Linux (storage0)
|
||||
hosts: storage0
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Bootstrap Python 3 on Alpine via raw command
|
||||
ansible.builtin.raw: apk update && apk add --no-cache python3 py3-pip
|
||||
changed_when: false
|
||||
|
||||
- name: Install nfs-utils and rpcbind
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- nfs-utils
|
||||
- rpcbind
|
||||
state: present
|
||||
|
||||
- name: Ensure exported root directories exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: "0777"
|
||||
loop:
|
||||
- /media
|
||||
- /torrents
|
||||
- /torrents/downloads
|
||||
- /torrents/config
|
||||
- /backups
|
||||
- /models
|
||||
- /mnt
|
||||
|
||||
- name: Create backward compatibility symlinks in /mnt
|
||||
ansible.builtin.file:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
state: link
|
||||
force: true
|
||||
loop:
|
||||
- { src: '/media', dest: '/mnt/media' }
|
||||
- { src: '/torrents', dest: '/mnt/torrents' }
|
||||
- { src: '/backups', dest: '/mnt/backups' }
|
||||
- { src: '/models', dest: '/mnt/models' }
|
||||
|
||||
- name: Configure /etc/exports for Kubernetes PV clients
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/exports
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
content: |
|
||||
/media 10.0.0.0/16(rw,sync,no_subtree_check,no_root_squash) 127.0.0.1(rw,sync,no_subtree_check,no_root_squash)
|
||||
/torrents 10.0.0.0/16(rw,sync,no_subtree_check,no_root_squash) 127.0.0.1(rw,sync,no_subtree_check,no_root_squash)
|
||||
/backups 10.0.0.0/16(rw,sync,no_subtree_check,no_root_squash) 127.0.0.1(rw,sync,no_subtree_check,no_root_squash)
|
||||
/models 10.0.0.0/16(rw,sync,no_subtree_check,no_root_squash) 127.0.0.1(rw,sync,no_subtree_check,no_root_squash)
|
||||
notify: Reload NFS exports
|
||||
|
||||
- name: Enable and start rpcbind service
|
||||
ansible.builtin.service:
|
||||
name: rpcbind
|
||||
enabled: true
|
||||
state: started
|
||||
|
||||
- name: Enable and start nfs service
|
||||
ansible.builtin.service:
|
||||
name: nfs
|
||||
enabled: true
|
||||
state: started
|
||||
|
||||
handlers:
|
||||
- name: Reload NFS exports
|
||||
ansible.builtin.command: exportfs -ra
|
||||
changed_when: false
|
||||
83
deploy.sh
Executable file
83
deploy.sh
Executable file
|
|
@ -0,0 +1,83 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "${REPO_ROOT}/scripts/lib/common.sh"
|
||||
|
||||
COMMAND="${1:-help}"
|
||||
|
||||
case "${COMMAND}" in
|
||||
up)
|
||||
shift
|
||||
target="${1:-all}"
|
||||
case "${target}" in
|
||||
host) "${REPO_ROOT}/scripts/layers/00_host.sh" ;;
|
||||
net) "${REPO_ROOT}/scripts/layers/01_net.sh" ;;
|
||||
tier0) "${REPO_ROOT}/scripts/layers/02_tier0.sh" ;;
|
||||
talos) "${REPO_ROOT}/scripts/layers/03_talos.sh" ;;
|
||||
apps) "${REPO_ROOT}/scripts/layers/04_apps.sh" ;;
|
||||
all)
|
||||
"${REPO_ROOT}/scripts/layers/00_host.sh"
|
||||
"${REPO_ROOT}/scripts/layers/01_net.sh"
|
||||
"${REPO_ROOT}/scripts/layers/02_tier0.sh"
|
||||
"${REPO_ROOT}/scripts/layers/03_talos.sh"
|
||||
"${REPO_ROOT}/scripts/layers/04_apps.sh"
|
||||
log_ok "Вся инфраструктура полностью развернута!"
|
||||
;;
|
||||
*)
|
||||
log_err "Неизвестный слой: ${target}. Доступны: host, net, tier0, talos, apps, all"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
unseal)
|
||||
ensure_prerequisites
|
||||
unseal_vault
|
||||
;;
|
||||
clean)
|
||||
rm -f "${RAM_CACHE}"
|
||||
log_ok "Секреты безопасно удалены из RAM."
|
||||
;;
|
||||
gc)
|
||||
"${REPO_ROOT}/scripts/layers/gc.sh"
|
||||
;;
|
||||
reset|nuke)
|
||||
"${REPO_ROOT}/scripts/layers/reset.sh"
|
||||
;;
|
||||
state)
|
||||
shift || true
|
||||
"${REPO_ROOT}/scripts/collect_state.sh" "$@"
|
||||
;;
|
||||
plan)
|
||||
ensure_prerequisites
|
||||
load_secrets_to_ram
|
||||
cd "${REPO_ROOT}/tofu" && tofu plan
|
||||
;;
|
||||
apply|a)
|
||||
ensure_prerequisites
|
||||
load_secrets_to_ram
|
||||
unseal_vault
|
||||
shift || true
|
||||
cd "${REPO_ROOT}/tofu" && tofu apply "$@"
|
||||
;;
|
||||
help|--help|-h)
|
||||
cat <<EOF
|
||||
Sovereign C2 Orchestrator (dep)
|
||||
|
||||
Команды:
|
||||
dep up [layer] Послойный деплой: host, net, tier0, talos, apps, all
|
||||
dep unseal Ручной ансил OpenBao + авто-синк токена в K8s
|
||||
dep state [module] Диагностика: workstation, pve, vps, vyos, tier0, k8s, all
|
||||
dep plan Tofu plan
|
||||
dep a / dep apply Tofu apply с авто-ансилом и синхронизацией токена
|
||||
dep clean Очистка кэша в /dev/shm
|
||||
dep reset Полный сброс всех VM/LXC до голого PVE
|
||||
dep gc Сборка мусора: удаление мертвых нод, зависших подов и сброс бэкоффа
|
||||
EOF
|
||||
;;
|
||||
*)
|
||||
ensure_prerequisites
|
||||
load_secrets_to_ram
|
||||
cd "${REPO_ROOT}/tofu" && tofu "$@"
|
||||
;;
|
||||
esac
|
||||
650
docs/hardware_snapshot.json
Normal file
650
docs/hardware_snapshot.json
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
{
|
||||
"cpu": {
|
||||
"lscpu": [
|
||||
{
|
||||
"field": "Architecture:",
|
||||
"data": "x86_64"
|
||||
},
|
||||
{
|
||||
"field": "CPU op-mode(s):",
|
||||
"data": "32-bit, 64-bit"
|
||||
},
|
||||
{
|
||||
"field": "Address sizes:",
|
||||
"data": "43 bits physical, 48 bits virtual"
|
||||
},
|
||||
{
|
||||
"field": "Byte Order:",
|
||||
"data": "Little Endian"
|
||||
},
|
||||
{
|
||||
"field": "CPU(s):",
|
||||
"data": "8"
|
||||
},
|
||||
{
|
||||
"field": "On-line CPU(s) list:",
|
||||
"data": "0-7"
|
||||
},
|
||||
{
|
||||
"field": "Vendor ID:",
|
||||
"data": "AuthenticAMD"
|
||||
},
|
||||
{
|
||||
"field": "Model name:",
|
||||
"data": "AMD Ryzen 5 3350GE with Radeon Vega Graphics"
|
||||
},
|
||||
{
|
||||
"field": "CPU family:",
|
||||
"data": "23"
|
||||
},
|
||||
{
|
||||
"field": "Model:",
|
||||
"data": "24"
|
||||
},
|
||||
{
|
||||
"field": "Thread(s) per core:",
|
||||
"data": "2"
|
||||
},
|
||||
{
|
||||
"field": "Core(s) per socket:",
|
||||
"data": "4"
|
||||
},
|
||||
{
|
||||
"field": "Socket(s):",
|
||||
"data": "1"
|
||||
},
|
||||
{
|
||||
"field": "Stepping:",
|
||||
"data": "1"
|
||||
},
|
||||
{
|
||||
"field": "Frequency boost:",
|
||||
"data": "enabled"
|
||||
},
|
||||
{
|
||||
"field": "CPU(s) scaling MHz:",
|
||||
"data": "94%"
|
||||
},
|
||||
{
|
||||
"field": "CPU max MHz:",
|
||||
"data": "3300.0000"
|
||||
},
|
||||
{
|
||||
"field": "CPU min MHz:",
|
||||
"data": "1400.0000"
|
||||
},
|
||||
{
|
||||
"field": "BogoMIPS:",
|
||||
"data": "6600.28"
|
||||
},
|
||||
{
|
||||
"field": "Flags:",
|
||||
"data": "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb hw_pstate ssbd ibpb vmmcall fsgsbase bmi1 avx2 smep bmi2 rdseed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif overflow_recov succor smca sev sev_es"
|
||||
},
|
||||
{
|
||||
"field": "Virtualization:",
|
||||
"data": "AMD-V"
|
||||
},
|
||||
{
|
||||
"field": "L1d cache:",
|
||||
"data": "128 KiB (4 instances)"
|
||||
},
|
||||
{
|
||||
"field": "L1i cache:",
|
||||
"data": "256 KiB (4 instances)"
|
||||
},
|
||||
{
|
||||
"field": "L2 cache:",
|
||||
"data": "2 MiB (4 instances)"
|
||||
},
|
||||
{
|
||||
"field": "L3 cache:",
|
||||
"data": "4 MiB (1 instance)"
|
||||
},
|
||||
{
|
||||
"field": "NUMA node(s):",
|
||||
"data": "1"
|
||||
},
|
||||
{
|
||||
"field": "NUMA node0 CPU(s):",
|
||||
"data": "0-7"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Gather data sampling:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Ghostwrite:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Indirect target selection:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Itlb multihit:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability L1tf:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Mds:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Meltdown:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Mmio stale data:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Old microcode:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Reg file data sampling:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Retbleed:",
|
||||
"data": "Mitigation; untrained return thunk; SMT vulnerable"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Spec rstack overflow:",
|
||||
"data": "Mitigation; Safe RET"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Spec store bypass:",
|
||||
"data": "Mitigation; Speculative Store Bypass disabled via prctl"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Spectre v1:",
|
||||
"data": "Mitigation; usercopy/swapgs barriers and __user pointer sanitization"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Spectre v2:",
|
||||
"data": "Mitigation; Retpolines; IBPB conditional; STIBP disabled; RSB filling; PBRSB-eIBRS Not affected; BHI Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Srbds:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Tsa:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Tsx async abort:",
|
||||
"data": "Not affected"
|
||||
},
|
||||
{
|
||||
"field": "Vulnerability Vmscape:",
|
||||
"data": "Mitigation; IBPB before exit to userspace"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ram_bytes": 39863885824,
|
||||
"disks": {
|
||||
"blockdevices": [
|
||||
{
|
||||
"name": "loop0",
|
||||
"size": "8G",
|
||||
"fstype": "ext4",
|
||||
"uuid": "1cda1590-5d27-4cab-858f-2666c19f45bd",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/loop0",
|
||||
"rota": false,
|
||||
"type": "loop"
|
||||
},
|
||||
{
|
||||
"name": "loop1",
|
||||
"size": "8G",
|
||||
"fstype": "ext4",
|
||||
"uuid": "b2e798db-809f-48d5-a97a-58a16d19de8c",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/loop1",
|
||||
"rota": false,
|
||||
"type": "loop"
|
||||
},
|
||||
{
|
||||
"name": "loop2",
|
||||
"size": "4G",
|
||||
"fstype": "ext4",
|
||||
"uuid": "a0dad42d-f88a-4983-88f9-6e8f9b8e5c74",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/loop2",
|
||||
"rota": false,
|
||||
"type": "loop"
|
||||
},
|
||||
{
|
||||
"name": "loop3",
|
||||
"size": "4G",
|
||||
"fstype": "ext4",
|
||||
"uuid": "5e9edd0b-1e43-4f26-96aa-aec3bd3b6d98",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/loop3",
|
||||
"rota": false,
|
||||
"type": "loop"
|
||||
},
|
||||
{
|
||||
"name": "loop4",
|
||||
"size": "2G",
|
||||
"fstype": "ext4",
|
||||
"uuid": "37dd032b-8381-4eec-b69f-a9748bc33777",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/loop4",
|
||||
"rota": false,
|
||||
"type": "loop"
|
||||
},
|
||||
{
|
||||
"name": "sda",
|
||||
"size": "1.8T",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": "TOSHIBA HDWA120",
|
||||
"serial": "27MWR2SAS",
|
||||
"path": "/dev/sda",
|
||||
"rota": true,
|
||||
"type": "disk",
|
||||
"children": [
|
||||
{
|
||||
"name": "sda1",
|
||||
"size": "1.8T",
|
||||
"fstype": "zfs_member",
|
||||
"uuid": "7540128891022881476",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sda1",
|
||||
"rota": true,
|
||||
"type": "part"
|
||||
},
|
||||
{
|
||||
"name": "sda9",
|
||||
"size": "8M",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sda9",
|
||||
"rota": true,
|
||||
"type": "part"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sdb",
|
||||
"size": "953.9G",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": "DEXP SSD C100 1Tb",
|
||||
"serial": "HGB446242911",
|
||||
"path": "/dev/sdb",
|
||||
"rota": false,
|
||||
"type": "disk",
|
||||
"children": [
|
||||
{
|
||||
"name": "sdb1",
|
||||
"size": "953.9G",
|
||||
"fstype": "zfs_member",
|
||||
"uuid": "1766286880976563783",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sdb1",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
},
|
||||
{
|
||||
"name": "sdb9",
|
||||
"size": "8M",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sdb9",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sdc",
|
||||
"size": "476.9G",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": "Patriot P210 512GB",
|
||||
"serial": "P210EDCB22092102722",
|
||||
"path": "/dev/sdc",
|
||||
"rota": false,
|
||||
"type": "disk",
|
||||
"children": [
|
||||
{
|
||||
"name": "sdc1",
|
||||
"size": "976M",
|
||||
"fstype": "vfat",
|
||||
"uuid": "9DAA-752C",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sdc1",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
},
|
||||
{
|
||||
"name": "sdc2",
|
||||
"size": "977M",
|
||||
"fstype": "linux_raid_member",
|
||||
"uuid": "e895a645-731a-c3f0-4f42-5bf822ece61e",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sdc2",
|
||||
"rota": false,
|
||||
"type": "part",
|
||||
"children": [
|
||||
{
|
||||
"name": "md0",
|
||||
"size": "976M",
|
||||
"fstype": "ext4",
|
||||
"uuid": "4326ce97-013c-48e0-9b89-08722f8b13d3",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/md0",
|
||||
"rota": false,
|
||||
"type": "raid1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sdc3",
|
||||
"size": "445.3G",
|
||||
"fstype": "linux_raid_member",
|
||||
"uuid": "b383b1c8-144c-322c-58ab-66a03745768a",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sdc3",
|
||||
"rota": false,
|
||||
"type": "part",
|
||||
"children": [
|
||||
{
|
||||
"name": "md1",
|
||||
"size": "445.1G",
|
||||
"fstype": "crypto_LUKS",
|
||||
"uuid": "d5ac7445-7491-4299-9cc5-22c316245793",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/md1",
|
||||
"rota": false,
|
||||
"type": "raid1",
|
||||
"children": [
|
||||
{
|
||||
"name": "md1_crypt",
|
||||
"size": "445.1G",
|
||||
"fstype": "ext4",
|
||||
"uuid": "aa4d959e-ebdb-4bd7-b8e9-5631a250da60",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/mapper/md1_crypt",
|
||||
"rota": false,
|
||||
"type": "crypt"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sdd",
|
||||
"size": "953.9G",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": "DEXP SSD C100 1Tb",
|
||||
"serial": "HGB443029148",
|
||||
"path": "/dev/sdd",
|
||||
"rota": false,
|
||||
"type": "disk",
|
||||
"children": [
|
||||
{
|
||||
"name": "sdd1",
|
||||
"size": "953.9G",
|
||||
"fstype": "zfs_member",
|
||||
"uuid": "1766286880976563783",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sdd1",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
},
|
||||
{
|
||||
"name": "sdd9",
|
||||
"size": "8M",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sdd9",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sde",
|
||||
"size": "447.1G",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": "HS-SSD-C100 480G",
|
||||
"serial": "30103741962",
|
||||
"path": "/dev/sde",
|
||||
"rota": false,
|
||||
"type": "disk",
|
||||
"children": [
|
||||
{
|
||||
"name": "sde1",
|
||||
"size": "976M",
|
||||
"fstype": "vfat",
|
||||
"uuid": "9DAB-4792",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sde1",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
},
|
||||
{
|
||||
"name": "sde2",
|
||||
"size": "977M",
|
||||
"fstype": "linux_raid_member",
|
||||
"uuid": "e895a645-731a-c3f0-4f42-5bf822ece61e",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sde2",
|
||||
"rota": false,
|
||||
"type": "part",
|
||||
"children": [
|
||||
{
|
||||
"name": "md0",
|
||||
"size": "976M",
|
||||
"fstype": "ext4",
|
||||
"uuid": "4326ce97-013c-48e0-9b89-08722f8b13d3",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/md0",
|
||||
"rota": false,
|
||||
"type": "raid1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sde3",
|
||||
"size": "445.2G",
|
||||
"fstype": "linux_raid_member",
|
||||
"uuid": "b383b1c8-144c-322c-58ab-66a03745768a",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sde3",
|
||||
"rota": false,
|
||||
"type": "part",
|
||||
"children": [
|
||||
{
|
||||
"name": "md1",
|
||||
"size": "445.1G",
|
||||
"fstype": "crypto_LUKS",
|
||||
"uuid": "d5ac7445-7491-4299-9cc5-22c316245793",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/md1",
|
||||
"rota": false,
|
||||
"type": "raid1",
|
||||
"children": [
|
||||
{
|
||||
"name": "md1_crypt",
|
||||
"size": "445.1G",
|
||||
"fstype": "ext4",
|
||||
"uuid": "aa4d959e-ebdb-4bd7-b8e9-5631a250da60",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/mapper/md1_crypt",
|
||||
"rota": false,
|
||||
"type": "crypt"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sdf",
|
||||
"size": "953.9G",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": "DEXP SSD C100 1024Gb",
|
||||
"serial": "MBM343145343",
|
||||
"path": "/dev/sdf",
|
||||
"rota": false,
|
||||
"type": "disk",
|
||||
"children": [
|
||||
{
|
||||
"name": "sdf1",
|
||||
"size": "953.9G",
|
||||
"fstype": "zfs_member",
|
||||
"uuid": "1766286880976563783",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sdf1",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
},
|
||||
{
|
||||
"name": "sdf9",
|
||||
"size": "8M",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/sdf9",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "zd0",
|
||||
"size": "4M",
|
||||
"fstype": "iso9660",
|
||||
"uuid": "2026-08-26-12-40-52-00",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/zd0",
|
||||
"rota": false,
|
||||
"type": "disk"
|
||||
},
|
||||
{
|
||||
"name": "zd16",
|
||||
"size": "100G",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/zd16",
|
||||
"rota": false,
|
||||
"type": "disk"
|
||||
},
|
||||
{
|
||||
"name": "zd32",
|
||||
"size": "100G",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/zd32",
|
||||
"rota": false,
|
||||
"type": "disk"
|
||||
},
|
||||
{
|
||||
"name": "zd48",
|
||||
"size": "10G",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/zd48",
|
||||
"rota": false,
|
||||
"type": "disk",
|
||||
"children": [
|
||||
{
|
||||
"name": "zd48p1",
|
||||
"size": "1M",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/zd48p1",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
},
|
||||
{
|
||||
"name": "zd48p2",
|
||||
"size": "256M",
|
||||
"fstype": "vfat",
|
||||
"uuid": "C283-D401",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/zd48p2",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
},
|
||||
{
|
||||
"name": "zd48p3",
|
||||
"size": "9G",
|
||||
"fstype": "ext4",
|
||||
"uuid": "c33ec994-5719-497b-a670-f3941f9a2792",
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/zd48p3",
|
||||
"rota": false,
|
||||
"type": "part"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "zd64",
|
||||
"size": "20G",
|
||||
"fstype": null,
|
||||
"uuid": null,
|
||||
"model": null,
|
||||
"serial": null,
|
||||
"path": "/dev/zd64",
|
||||
"rota": false,
|
||||
"type": "disk"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
51
docs/invariants.md
Normal file
51
docs/invariants.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Каноническая спецификация инвариантов Sovereign C2
|
||||
|
||||
**Статус документа:** Строгий стандарт
|
||||
**Назначение:** Определение фундаментальных правил, которые не могут быть нарушены ни при каких изменениях программного или аппаратного обеспечения. Любое техническое решение (выбор ОС, файловой системы, сетевого стека) должно доказывать соответствие данным инвариантам.
|
||||
**Формат кода:** `[ДОМЕН]-[НОМЕР]`. Код постоянен, эволюция требований отслеживается историей Git.
|
||||
|
||||
---
|
||||
|
||||
## Категория A: Хранение и данные (DATA)
|
||||
|
||||
* **DATA-01 (Изоляция и профилирование ввода-вывода):** Хранилище строго разделяется по паттернам доступа. Физические носители и параметры файловых систем обязаны математически соответствовать профилю нагрузки: мелкоблочный случайный ввод-вывод с критическими требованиями к задержкам физически изолирован от емкостных последовательных нагрузок, а геометрия хранилища выровнена по размеру транзакции потребителя для исключения эффекта усиления записи.
|
||||
* **DATA-02 (Абсолютная криптография покоя):** Все без исключения энергонезависимые носители информации криптографически защищены. Извлечение физического накопителя из вычислительного комплекса не должно раскрывать структуру, метаданные или содержимое данных.
|
||||
* **DATA-03 (Иммутабельность точек восстановления):** Резервные копии формируются как атомарные, криптографически запечатанные слепки состояния, не зависящие от работоспособности исходной файловой системы и доступные для валидации в изолированной среде.
|
||||
|
||||
---
|
||||
|
||||
## Категория B: Сеть и изоляция (NET)
|
||||
|
||||
* **NET-01 (Мультиплексирование физической среды):** Логические домены безопасности (внешний периметр, маршрутизация, управление, внутренние вычисления) полностью изолированы друг от друга на уровне канального протокола, независимо от количества доступных физических сетевых интерфейсов.
|
||||
* **NET-02 (L2 Fast-Path и скрытая плоскость данных):** Вычислительные узлы скрыты от внешних широковещательных доменов. При этом обмен данными между доверенными локальными клиентами и внутренними прикладными сервисами замыкается напрямую в общем L2-сегменте на скорости коммутатора, полностью минуя межсетевой экран и исключая нагрузку на процессор маршрутизатора.
|
||||
* **NET-03 (Запрет прямой эксфильтрации):** Ни один прикладной сервис не имеет права на самостоятельное установление исходящих соединений во внешние сети. Доставка любых внешних бинарных компонентов, зависимостей и образов ПО разрешена исключительно через контролируемые локальные кэширующие шлюзы.
|
||||
* **NET-04 (Обфускация транзитного трафика):** Любой исходящий трафик за пределы доверенного периметра должен быть инкапсулирован и криптографически замаскирован для предотвращения глубокого анализа пакетов (DPI), цензуры или активного зондирования промежуточными операторами связи.
|
||||
* **NET-05 (Топология наложенного управления):** Административный доступ к инфраструктуре осуществляется строго через криптографически аутентифицированную одноранговую наложенную сеть (Overlay Network), исключающую зависимость от таблиц маршрутизации физических пограничных маршрутизаторов.
|
||||
|
||||
---
|
||||
|
||||
## Категория C: Физическая безопасность и доступ (SEC)
|
||||
|
||||
* **SEC-01 (Устойчивость к физическому захвату):** Физический захват включенного или выключенного оборудования третьими лицами на месте установки не должен приводить к автоматической компрометации критических данных или ключей управления.
|
||||
* **SEC-02 (Стойкость при досмотре клиентов):** Компрометация или принудительный досмотр мобильных и клиентских устройств за пределами доверенного периметра не должны раскрывать факт наличия, архитектуру или содержимое приватных сервисов.
|
||||
* **SEC-03 (Энергозависимость секретов):** Любые криптографические ключи, пароли и токены доступа существуют исключительно в энергозависимой памяти (RAM). Запись секретов в открытом виде на постоянные носители строго запрещена на всех этапах жизненного цикла инфраструктуры.
|
||||
* **SEC-04 (Автономность холодной загрузки):** Базовый слой инфраструктуры обязан корректно инициализироваться в условиях полного отсутствия доступа к глобальной сети, опираясь исключительно на доверенную локальную среду и энергозависимую инъекцию мастер-ключей авторизованным оператором.
|
||||
* **SEC-05 (Автономность клиентских терминалов):** Отказ, обесточивание или недоступность основного вычислительного комплекса не должны блокировать доступ пользователя к локально закэшированным критическим учетным данным и ключам на клиентских терминалах (ноутбук, смартфон).
|
||||
|
||||
---
|
||||
|
||||
## Категория D: Вычисления и отказоустойчивость (COMP)
|
||||
|
||||
* **COMP-01 (Детерминизм планировщика):** Компоненты управления (Control Plane) и маршрутизации получают строгие гарантии процессорного времени. Пользовательские и прикладные нагрузки утилизируют только остаточные вычислительные такты и не могут вызвать голодание системных процессов.
|
||||
* **COMP-02 (Строгое бюджетирование памяти):** Оперативная память распределяется квотами с обязательным аппаратным резервом. Каждому домену (маршрутизация, кэш файловой системы, управление, вычисления) установлен жесткий лимит для предотвращения каскадных отказов по исчерпанию памяти (OOM-шторм).
|
||||
* **COMP-03 (Гарантии восстановления из пепла):** При полной физической гибели основного оборудования допустима потеря данных не более чем за 7 дней (RPO ≤ 7 дней). Восстановление рабочего состояния на новом оборудовании должно выполняться оффлайн, используя исключительно холодные резервные копии и мастер-ключ.
|
||||
* **COMP-04 (N-Node Elasticity):** Архитектура индифферентна к количеству и вычислительной мощности узлов. Система обязана полноценно функционировать на одном маломощном устройстве, сохраняя способность прозрачно подключать разнородные вычислительные узлы без изменения сетевой модели и логики работы сервисов.
|
||||
|
||||
---
|
||||
|
||||
## Категория E: Управление и источник правды (SSOT)
|
||||
|
||||
* **SSOT-01 (Идемпотентная декларативность):** Весь жизненный цикл инфраструктуры (от создания дисков до конфигурации приложений) описан в виде исполняемого кода. Процесс применения конфигурации обязан быть конвергентным и идемпотентным (безопасным для повторного запуска).
|
||||
* **SSOT-02 (Локализация источника правды):** Механизмы непрерывной доставки и хранилища конфигураций (Source of Truth) размещаются внутри управляемого периметра. Инфраструктура развертывает и обновляет саму себя без привлечения внешних публичных репозиториев или облачных CI/CD конвейеров.
|
||||
* **SSOT-03 (Иммутабельность вычислительных узлов):** Любые ручные изменения состояния внутри операционных систем вычислительных узлов запрещены. Обновление или исправление конфигурации достигается исключительно пересозданием вычислительного ресурса на основе эталонного образа.
|
||||
* **SSOT-04 (Автономная телеметрия):** Непрерывный аудит, мониторинг и сбор телеметрии замкнуты строго внутри доверенного периметра. Любая эксфильтрация метрик, логов или событий безопасности во внешние облачные платформы категорически запрещена.
|
||||
382
docs/topology.yaml
Normal file
382
docs/topology.yaml
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
hardware:
|
||||
cpu:
|
||||
architecture: "x86_64"
|
||||
model: "AMD Ryzen 5 3350GE with Radeon Vega Graphics"
|
||||
threads: 8
|
||||
cores: 4
|
||||
ram:
|
||||
total_bytes: 39863885824
|
||||
budgeting_gb:
|
||||
reserved_apu: 0.064
|
||||
arc_cache_limit: 4.0
|
||||
vyos_podman: 1.0
|
||||
lxc_tier0: 2.5
|
||||
talos_master: 2.5
|
||||
talos_workers: 20.0
|
||||
oom_headroom: 9.936
|
||||
storage:
|
||||
pools:
|
||||
astra:
|
||||
type: "zfs_raidz1"
|
||||
media: "ssd"
|
||||
devices:
|
||||
- "/dev/disk/by-id/ata-DEXP_SSD_C100_1Tb_HGB446242911"
|
||||
- "/dev/disk/by-id/ata-DEXP_SSD_C100_1Tb_HGB443029148"
|
||||
- "/dev/disk/by-id/ata-DEXP_SSD_C100_1024Gb_MBM343145343"
|
||||
terra:
|
||||
type: "zfs_single"
|
||||
media: "hdd"
|
||||
devices:
|
||||
- "/dev/disk/by-id/ata-TOSHIBA_HDWA120_27MWR2SAS"
|
||||
local:
|
||||
type: "mdadm_luks_ext4"
|
||||
media: "ssd"
|
||||
devices:
|
||||
- "/dev/disk/by-id/ata-Patriot_P210_512GB_P210EDCB22092102722"
|
||||
- "/dev/disk/by-id/ata-HS-SSD-C100_480G_30103741962"
|
||||
|
||||
network:
|
||||
vlans:
|
||||
vlan_10:
|
||||
id: 10
|
||||
name: "TIER0"
|
||||
cidr: "10.0.10.0/24"
|
||||
gateway: "10.0.10.1"
|
||||
policy: "strict_internal"
|
||||
vlan_20:
|
||||
id: 20
|
||||
name: "K8S"
|
||||
cidr: "10.0.20.0/24"
|
||||
gateway: "10.0.20.1"
|
||||
policy: "k8s_overlay"
|
||||
vlan_30:
|
||||
id: 30
|
||||
name: "LAN_CLIENTS"
|
||||
cidr: "10.0.30.0/24"
|
||||
gateway: "10.0.30.1"
|
||||
policy: "l2_fast_path_vip"
|
||||
vlan_40:
|
||||
id: 40
|
||||
name: "IOT"
|
||||
cidr: "10.0.40.0/24"
|
||||
gateway: "10.0.40.1"
|
||||
policy: "isolated_no_internet"
|
||||
vlan_99:
|
||||
id: 99
|
||||
name: "WAN_TRUNK"
|
||||
cidr: "192.168.1.0/24"
|
||||
gateway: "192.168.1.1"
|
||||
policy: "external_egress"
|
||||
tier0_ips:
|
||||
vyos: "10.0.10.1"
|
||||
dns0: "10.0.10.11"
|
||||
vault0: "10.0.10.12"
|
||||
git0: "10.0.10.13"
|
||||
storage0: "10.0.10.14"
|
||||
registry0: "10.0.10.15"
|
||||
|
||||
infrastructure_nodes:
|
||||
- id: 100
|
||||
name: "vyos-router"
|
||||
type: "vm"
|
||||
role: "edge_router"
|
||||
vcpu: 2
|
||||
ram_mb: 1024
|
||||
disk_gb: 10
|
||||
pool: "astra"
|
||||
- id: 101
|
||||
name: "dns0"
|
||||
type: "lxc"
|
||||
role: "dns_server"
|
||||
vcpu: 1
|
||||
ram_mb: 512
|
||||
disk_gb: 2
|
||||
pool: "local"
|
||||
- id: 102
|
||||
name: "vault0"
|
||||
type: "lxc"
|
||||
role: "secrets_manager"
|
||||
vcpu: 1
|
||||
ram_mb: 512
|
||||
disk_gb: 4
|
||||
pool: "local"
|
||||
- id: 103
|
||||
name: "git0"
|
||||
type: "lxc"
|
||||
role: "gitops_repo"
|
||||
vcpu: 2
|
||||
ram_mb: 1024
|
||||
disk_gb: 8
|
||||
pool: "local"
|
||||
- id: 104
|
||||
name: "storage0"
|
||||
type: "lxc"
|
||||
role: "nas_storage"
|
||||
vcpu: 2
|
||||
ram_mb: 1024
|
||||
disk_gb: 4
|
||||
pool: "local"
|
||||
mounts:
|
||||
- path: "/mnt/media"
|
||||
volume: "/terra/media"
|
||||
- path: "/mnt/torrents"
|
||||
volume: "/terra/torrents"
|
||||
- path: "/mnt/backups"
|
||||
volume: "/terra/vault"
|
||||
- id: 105
|
||||
name: "registry0"
|
||||
type: "lxc"
|
||||
role: "oci_registry"
|
||||
vcpu: 2
|
||||
ram_mb: 1024
|
||||
disk_gb: 8
|
||||
pool: "local"
|
||||
mounts:
|
||||
- path: "/mnt/registry"
|
||||
pool: "terra"
|
||||
volume: "/terra/registry"
|
||||
- id: 201
|
||||
name: "talos-master-1"
|
||||
type: "vm"
|
||||
role: "k8s_control_plane"
|
||||
vcpu: 2
|
||||
ram_mb: 2560
|
||||
disk_gb: 20
|
||||
pool: "astra"
|
||||
- id: 202
|
||||
name: "talos-worker-1"
|
||||
type: "vm"
|
||||
role: "k8s_worker"
|
||||
vcpu: 4
|
||||
ram_mb: 10240
|
||||
disk_gb: 100
|
||||
pool: "astra"
|
||||
- id: 203
|
||||
name: "talos-worker-2"
|
||||
type: "vm"
|
||||
role: "k8s_worker"
|
||||
vcpu: 4
|
||||
ram_mb: 10240
|
||||
disk_gb: 100
|
||||
pool: "astra"
|
||||
|
||||
workloads:
|
||||
- name: "cilium_cni"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "traefik_v3"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "csi_drivers"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "IO-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "fluxcd"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "Idle"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "kyverno"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "tetragon"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "vector_agent"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "IO-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "crowdsec"
|
||||
runtime: "k8s"
|
||||
state_type: "Micro-Stateful"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "PVC"
|
||||
db_dependency: "SQLite"
|
||||
- name: "postgresql"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "IO-Bound"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "ZVOL"
|
||||
db_dependency: "None"
|
||||
- name: "redis_cache"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "RAM-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "authentik_sso"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "Postgres, Redis"
|
||||
- name: "vaultwarden"
|
||||
runtime: "k8s"
|
||||
state_type: "Micro-Stateful"
|
||||
compute_profile: "Idle"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "ZVOL"
|
||||
db_dependency: "SQLite"
|
||||
- name: "immich_system"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "ZVOL"
|
||||
media_storage_medium: "SSD"
|
||||
media_storage_fs: "PVC"
|
||||
db_dependency: "Postgres, Redis"
|
||||
- name: "paperless_ngx"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "PVC"
|
||||
db_dependency: "Postgres, Redis"
|
||||
- name: "netbox_dcim"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "Idle"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "Postgres, Redis"
|
||||
- name: "opencloud"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "IO-Bound"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "PVC"
|
||||
db_dependency: "Postgres, Redis"
|
||||
- name: "homebox"
|
||||
runtime: "k8s"
|
||||
state_type: "Micro-Stateful"
|
||||
compute_profile: "Idle"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "ZVOL"
|
||||
db_dependency: "SQLite"
|
||||
- name: "spoolman"
|
||||
runtime: "k8s"
|
||||
state_type: "Micro-Stateful"
|
||||
compute_profile: "Idle"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "ZVOL"
|
||||
db_dependency: "SQLite"
|
||||
- name: "victoriametrics"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "IO-Bound"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "PVC"
|
||||
db_dependency: "None"
|
||||
- name: "grafana_loki"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "IO-Bound"
|
||||
storage_medium: "HDD"
|
||||
storage_fs: "Dataset"
|
||||
db_dependency: "None"
|
||||
- name: "grafana_ui"
|
||||
runtime: "k8s"
|
||||
state_type: "Micro-Stateful"
|
||||
compute_profile: "Idle"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "PVC"
|
||||
db_dependency: "SQLite"
|
||||
- name: "pixie"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "RAM-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "qbittorrent"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "IO-Bound"
|
||||
storage_medium: "HDD"
|
||||
storage_fs: "Dataset"
|
||||
db_dependency: "None"
|
||||
- name: "jellyfin"
|
||||
runtime: "bare-metal"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "IO-Bound"
|
||||
storage_medium: "HDD"
|
||||
storage_fs: "Dataset"
|
||||
db_dependency: "None"
|
||||
- name: "kiwix_reader"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "IO-Bound"
|
||||
storage_medium: "HDD"
|
||||
storage_fs: "Dataset"
|
||||
db_dependency: "None"
|
||||
- name: "sure_finance"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "Idle"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "Postgres"
|
||||
- name: "searxng"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "act_runner_ci"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "karakeep"
|
||||
runtime: "k8s"
|
||||
state_type: "Micro-Stateful"
|
||||
compute_profile: "Idle"
|
||||
storage_medium: "SSD"
|
||||
storage_fs: "PVC"
|
||||
db_dependency: "SQLite"
|
||||
- name: "transmute"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateless"
|
||||
compute_profile: "CPU-Bound"
|
||||
storage_medium: "RAM"
|
||||
storage_fs: "tmpfs"
|
||||
db_dependency: "None"
|
||||
- name: "printstash"
|
||||
runtime: "k8s"
|
||||
state_type: "Stateful"
|
||||
compute_profile: "Idle"
|
||||
storage_medium: "HDD"
|
||||
storage_fs: "Dataset"
|
||||
db_dependency: "Postgres"
|
||||
21
kubernetes/apps/authentik/credentials.yaml
Normal file
21
kubernetes/apps/authentik/credentials.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: authentik-credentials
|
||||
namespace: authentik
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: authentik-credentials
|
||||
data:
|
||||
- secretKey: secret_key
|
||||
remoteRef:
|
||||
key: secret/authentik
|
||||
property: secret_key
|
||||
- secretKey: postgresql_password
|
||||
remoteRef:
|
||||
key: secret/authentik
|
||||
property: postgresql_password
|
||||
132
kubernetes/apps/authentik/deployment.yaml
Normal file
132
kubernetes/apps/authentik/deployment.yaml
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: authentik
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: authentik-server
|
||||
namespace: authentik
|
||||
spec:
|
||||
serviceName: authentik-server
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: authentik-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: authentik-server
|
||||
spec:
|
||||
containers:
|
||||
- name: server
|
||||
image: ghcr.io/goauthentik/server:2026.8.3
|
||||
args: ["server"]
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 9000
|
||||
- name: https
|
||||
containerPort: 9443
|
||||
env:
|
||||
- name: AUTHENTIK_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: authentik-credentials
|
||||
key: secret_key
|
||||
- name: AUTHENTIK_POSTGRESQL__HOST
|
||||
value: postgres-core.databases.svc.cluster.local
|
||||
- name: AUTHENTIK_POSTGRESQL__NAME
|
||||
value: authentik
|
||||
- name: AUTHENTIK_POSTGRESQL__USER
|
||||
value: authentik
|
||||
- name: AUTHENTIK_POSTGRESQL__PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: authentik-credentials
|
||||
key: postgresql_password
|
||||
- name: AUTHENTIK_REDIS__HOST
|
||||
value: redis-core.databases.svc.cluster.local
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: authentik-server
|
||||
namespace: authentik
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 9000
|
||||
- name: https
|
||||
port: 443
|
||||
targetPort: 9443
|
||||
selector:
|
||||
app: authentik-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: authentik-worker
|
||||
namespace: authentik
|
||||
spec:
|
||||
serviceName: authentik-server
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: authentik-worker
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: authentik-worker
|
||||
spec:
|
||||
containers:
|
||||
- name: worker
|
||||
image: ghcr.io/goauthentik/server:2026.8.3
|
||||
args: ["worker"]
|
||||
env:
|
||||
- name: AUTHENTIK_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: authentik-credentials
|
||||
key: secret_key
|
||||
- name: AUTHENTIK_POSTGRESQL__HOST
|
||||
value: postgres-core.databases.svc.cluster.local
|
||||
- name: AUTHENTIK_POSTGRESQL__NAME
|
||||
value: authentik
|
||||
- name: AUTHENTIK_POSTGRESQL__USER
|
||||
value: authentik
|
||||
- name: AUTHENTIK_POSTGRESQL__PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: authentik-credentials
|
||||
key: postgresql_password
|
||||
- name: AUTHENTIK_REDIS__HOST
|
||||
value: redis-core.databases.svc.cluster.local
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: authentik
|
||||
namespace: authentik
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- auth.svo88.space
|
||||
secretName: auth-svo88-tls
|
||||
rules:
|
||||
- host: auth.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: authentik-server
|
||||
port:
|
||||
number: 80
|
||||
251
kubernetes/apps/core-db/core-db.yaml
Normal file
251
kubernetes/apps/core-db/core-db.yaml
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: databases
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: postgres-credentials
|
||||
namespace: databases
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: postgres-credentials
|
||||
data:
|
||||
- secretKey: POSTGRES_PASSWORD
|
||||
remoteRef:
|
||||
key: secret/postgres
|
||||
property: POSTGRES_PASSWORD
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: postgres-core
|
||||
namespace: databases
|
||||
spec:
|
||||
serviceName: postgres-core
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: postgres-core
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: postgres-core
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: postgres:16-alpine
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
env:
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-credentials
|
||||
key: POSTGRES_PASSWORD
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 2048Mi
|
||||
volumeMounts:
|
||||
- name: postgres-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: postgres-data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-db
|
||||
resources:
|
||||
requests:
|
||||
storage: 100Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: postgres-core
|
||||
namespace: databases
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: 5432
|
||||
selector:
|
||||
app: postgres-core
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: redis-core
|
||||
serviceName: redis-core
|
||||
namespace: databases
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: redis-core
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis-core
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 400Mi
|
||||
volumeMounts:
|
||||
- name: redis-data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: redis-data
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis-core
|
||||
serviceName: redis-core
|
||||
namespace: databases
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 6379
|
||||
targetPort: 6379
|
||||
selector:
|
||||
app: redis-core
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: all-db-passwords
|
||||
namespace: databases
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: all-db-passwords
|
||||
data:
|
||||
- secretKey: AUTHENTIK_PASS
|
||||
remoteRef:
|
||||
key: secret/authentik
|
||||
property: postgresql_password
|
||||
- secretKey: IMMICH_PASS
|
||||
remoteRef:
|
||||
key: secret/immich
|
||||
property: DB_PASSWORD
|
||||
- secretKey: PAPERLESS_PASS
|
||||
remoteRef:
|
||||
key: secret/paperless
|
||||
property: PAPERLESS_DBPASS
|
||||
- secretKey: NETBOX_PASS
|
||||
remoteRef:
|
||||
key: secret/netbox
|
||||
property: DB_PASSWORD
|
||||
- secretKey: SURE_PASS
|
||||
remoteRef:
|
||||
key: secret/sure
|
||||
property: DB_PASSWORD
|
||||
- secretKey: PRINTSTASH_PASS
|
||||
remoteRef:
|
||||
key: secret/printstash
|
||||
property: DB_PASSWORD
|
||||
- secretKey: INVIDIOUS_PASS
|
||||
remoteRef:
|
||||
key: secret/invidious
|
||||
property: DB_PASSWORD
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: postgres-init-databases
|
||||
namespace: databases
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: db-init
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
- name: PGPASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-credentials
|
||||
key: POSTGRES_PASSWORD
|
||||
- name: AUTHENTIK_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: all-db-passwords
|
||||
key: AUTHENTIK_PASS
|
||||
- name: IMMICH_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: all-db-passwords
|
||||
key: IMMICH_PASS
|
||||
- name: PAPERLESS_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: all-db-passwords
|
||||
key: PAPERLESS_PASS
|
||||
- name: NETBOX_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: all-db-passwords
|
||||
key: NETBOX_PASS
|
||||
- name: SURE_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: all-db-passwords
|
||||
key: SURE_PASS
|
||||
- name: PRINTSTASH_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: all-db-passwords
|
||||
key: PRINTSTASH_PASS
|
||||
- name: INVIDIOUS_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: all-db-passwords
|
||||
key: INVIDIOUS_PASS
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
until pg_isready -h postgres-core -p 5432 -U postgres; do sleep 2; done
|
||||
create_db() {
|
||||
local user=$1
|
||||
local pass=$2
|
||||
local db=$3
|
||||
psql -h postgres-core -U postgres -tc "SELECT 1 FROM pg_user WHERE usename = '$user'" | grep -q 1 || \
|
||||
psql -h postgres-core -U postgres -c "CREATE USER $user WITH PASSWORD '$pass';"
|
||||
psql -h postgres-core -U postgres -c "ALTER USER $user WITH PASSWORD '$pass';"
|
||||
psql -h postgres-core -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = '$db'" | grep -q 1 || \
|
||||
psql -h postgres-core -U postgres -c "CREATE DATABASE $db OWNER $user;"
|
||||
}
|
||||
create_db "authentik" "$AUTHENTIK_PASS" "authentik"
|
||||
create_db "immich" "$IMMICH_PASS" "immich"
|
||||
create_db "paperless" "$PAPERLESS_PASS" "paperless"
|
||||
create_db "netbox" "$NETBOX_PASS" "netbox"
|
||||
create_db "sure" "$SURE_PASS" "sure_finance"
|
||||
create_db "printstash" "$PRINTSTASH_PASS" "printstash"
|
||||
create_db "invidious" "$INVIDIOUS_PASS" "invidious"
|
||||
echo "Все базы данных успешно инициализированы!"
|
||||
311
kubernetes/apps/dashboard/deployment.yaml
Normal file
311
kubernetes/apps/dashboard/deployment.yaml
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: dashboard-html
|
||||
namespace: tools
|
||||
data:
|
||||
index.html: |
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ATLAS</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #090a0f;
|
||||
--card-bg: #10121a;
|
||||
--border: #1a1d2b;
|
||||
--text: #cdd6f4;
|
||||
--text-dim: #6c7086;
|
||||
--accent: #89b4fa;
|
||||
}
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
background-color: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
padding: 2.5rem 2rem;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.container { max-width: 1400px; margin: 0 auto; }
|
||||
header { margin-bottom: 2rem; }
|
||||
.title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.15em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
.search-box {
|
||||
margin: 1.5rem 0 2.5rem 0;
|
||||
position: relative;
|
||||
}
|
||||
input[type="text"] {
|
||||
width: 100%;
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
padding: 0.85rem 1.25rem;
|
||||
color: var(--text);
|
||||
font-family: inherit;
|
||||
font-size: 0.95rem;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
input[type="text"]:focus { border-color: var(--accent); }
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 0.8rem;
|
||||
color: var(--accent);
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.35rem;
|
||||
border-bottom: 1px dashed var(--border);
|
||||
}
|
||||
.links { display: flex; flex-direction: column; gap: 0.5rem; }
|
||||
.link-card {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
padding: 0.75rem 1rem;
|
||||
text-decoration: none;
|
||||
color: var(--text);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
.link-card:hover, .link-card.active {
|
||||
border-color: var(--accent);
|
||||
background: #141724;
|
||||
transform: translateX(4px);
|
||||
}
|
||||
.link-name { font-size: 0.9rem; font-weight: 500; }
|
||||
.link-desc { font-size: 0.75rem; color: var(--text-dim); }
|
||||
.hidden { display: none !important; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<div class="title">ATLAS</div>
|
||||
</header>
|
||||
|
||||
<div class="search-box">
|
||||
<input type="text" id="search" placeholder="..." autofocus autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="grid" id="mainGrid">
|
||||
<div class="section" data-section>
|
||||
<div class="section-title">01 // CORE & INFRA</div>
|
||||
<div class="links">
|
||||
<a href="https://pve.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Proxmox VE</div><div class="link-desc">Hypervisor Node (pve0)</div></div>
|
||||
</a>
|
||||
<a href="https://dns.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Technitium DNS</div><div class="link-desc">Authoritative / DoT DNS</div></div>
|
||||
</a>
|
||||
<a href="https://vault.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">OpenBao Vault</div><div class="link-desc">RAM Secrets Engine</div></div>
|
||||
</a>
|
||||
<a href="https://git.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Forgejo GitOps</div><div class="link-desc">Source of Truth Repo</div></div>
|
||||
</a>
|
||||
<a href="https://zot.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Zot Registry</div><div class="link-desc">OCI Container Cache</div></div>
|
||||
</a>
|
||||
<a href="https://netbox.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">NetBox DCIM</div><div class="link-desc">IPAM & Network Assets</div></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" data-section>
|
||||
<div class="section-title">02 // SERVICES & DATA</div>
|
||||
<div class="links">
|
||||
<a href="https://paperless.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Paperless-ngx</div><div class="link-desc">OCR Document Archive</div></div>
|
||||
</a>
|
||||
<a href="https://opencloud.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">OpenCloud</div><div class="link-desc">Encrypted Cloud Storage</div></div>
|
||||
</a>
|
||||
<a href="https://vw.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Vaultwarden</div><div class="link-desc">Bitwarden Password Vault</div></div>
|
||||
</a>
|
||||
<a href="https://auth.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Authentik SSO</div><div class="link-desc">Identity & ForwardAuth</div></div>
|
||||
</a>
|
||||
<a href="https://finance.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Sure Finance</div><div class="link-desc">Personal Accounting</div></div>
|
||||
</a>
|
||||
<a href="https://search.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">SearXNG</div><div class="link-desc">Private Meta-Search</div></div>
|
||||
</a>
|
||||
<a href="https://homebox.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Homebox</div><div class="link-desc">Inventory & Asset Tracking</div></div>
|
||||
</a>
|
||||
<a href="https://spoolman.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Spoolman</div><div class="link-desc">3D Filament Manager</div></div>
|
||||
</a>
|
||||
<a href="https://printstash.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Printstash</div><div class="link-desc">3D Model Stash</div></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" data-section>
|
||||
<div class="section-title">03 // MEDIA & ENTERTAINMENT</div>
|
||||
<div class="links">
|
||||
<a href="https://immich.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Immich Photos</div><div class="link-desc">Photo & Video Archive</div></div>
|
||||
</a>
|
||||
<a href="https://jellyfin.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Jellyfin</div><div class="link-desc">Courses & Media Stream</div></div>
|
||||
</a>
|
||||
<a href="https://mtube.svo88.space" class="link-card" target="_blank">
|
||||
<div><div class="link-name">MeTube</div><div class="link-desc">Video Course Downloader</div></div>
|
||||
</a>
|
||||
<a href="http://10.0.30.200:8080" class="link-card" target="_blank">
|
||||
<div><div class="link-name">qBittorrent</div><div class="link-desc">NFS Bulk Downloader</div></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" data-section>
|
||||
<div class="section-title">04 // NETWORK & EXTERNAL</div>
|
||||
<div class="links">
|
||||
<a href="https://153.76.194.24:8443" class="link-card" target="_blank">
|
||||
<div><div class="link-name">Fin21 Perimeter</div><div class="link-desc">Edge VPS Fallback</div></div>
|
||||
</a>
|
||||
<a href="https://github.com" class="link-card" target="_blank">
|
||||
<div><div class="link-name">GitHub</div><div class="link-desc">External Repositories</div></div>
|
||||
</a>
|
||||
<a href="https://ntc.party" class="link-card" target="_blank">
|
||||
<div><div class="link-name">NTC Party</div><div class="link-desc">DPI & Censorship Research</div></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const search = document.getElementById('search');
|
||||
const cards = Array.from(document.querySelectorAll('.link-card'));
|
||||
const sections = Array.from(document.querySelectorAll('[data-section]'));
|
||||
|
||||
search.addEventListener('input', (e) => {
|
||||
const val = e.target.value.toLowerCase().trim();
|
||||
cards.forEach(c => {
|
||||
const text = (c.querySelector('.link-name').textContent + ' ' + c.querySelector('.link-desc').textContent).toLowerCase();
|
||||
if (text.includes(val)) {
|
||||
c.classList.remove('hidden');
|
||||
} else {
|
||||
c.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
sections.forEach(s => {
|
||||
const hasVisible = s.querySelectorAll('.link-card:not(.hidden)').length > 0;
|
||||
s.style.display = hasVisible ? 'block' : 'none';
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === '/' && document.activeElement !== search) {
|
||||
e.preventDefault();
|
||||
search.focus();
|
||||
search.select();
|
||||
} else if (e.key === 'Escape') {
|
||||
search.value = '';
|
||||
search.dispatchEvent(new Event('input'));
|
||||
search.blur();
|
||||
} else if (e.key === 'Enter') {
|
||||
const first = document.querySelector('.link-card:not(.hidden)');
|
||||
if (first) window.open(first.href, '_blank');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: dashboard
|
||||
namespace: tools
|
||||
labels:
|
||||
app: dashboard
|
||||
spec:
|
||||
serviceName: dashboard
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: dashboard
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: dashboard
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- containerPort: 80
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 16Mi
|
||||
limits:
|
||||
cpu: 50m
|
||||
memory: 32Mi
|
||||
volumeMounts:
|
||||
- name: html
|
||||
mountPath: /usr/share/nginx/html
|
||||
volumes:
|
||||
- name: html
|
||||
configMap:
|
||||
name: dashboard-html
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: dashboard
|
||||
namespace: tools
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: dashboard
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: dashboard
|
||||
namespace: tools
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- dash.svo88.space
|
||||
secretName: dash-svo88-tls
|
||||
rules:
|
||||
- host: dash.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: dashboard
|
||||
port:
|
||||
number: 80
|
||||
109
kubernetes/apps/homebox/deployment.yaml
Normal file
109
kubernetes/apps/homebox/deployment.yaml
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: homebox-data-pvc
|
||||
namespace: tools
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: homebox-credentials
|
||||
namespace: tools
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: homebox-credentials
|
||||
data:
|
||||
- secretKey: HBOX_AUTH_API_KEY_PEPPER
|
||||
remoteRef:
|
||||
key: secret/homebox
|
||||
property: HBOX_AUTH_API_KEY_PEPPER
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: homebox
|
||||
namespace: tools
|
||||
spec:
|
||||
serviceName: homebox
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: homebox
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: homebox
|
||||
spec:
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: homebox
|
||||
image: ghcr.io/sysadminsmedia/homebox:latest
|
||||
ports:
|
||||
- containerPort: 7745
|
||||
env:
|
||||
- name: HBOX_MODE
|
||||
value: "production"
|
||||
- name: HBOX_AUTH_API_KEY_PEPPER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: homebox-credentials
|
||||
key: HBOX_AUTH_API_KEY_PEPPER
|
||||
volumeMounts:
|
||||
- name: homebox-data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: homebox-data
|
||||
persistentVolumeClaim:
|
||||
claimName: homebox-data-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: homebox
|
||||
namespace: tools
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 7745
|
||||
targetPort: 7745
|
||||
selector:
|
||||
app: homebox
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: homebox
|
||||
namespace: tools
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- homebox.svo88.space
|
||||
secretName: homebox-svo88-tls
|
||||
rules:
|
||||
- host: homebox.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: homebox
|
||||
port:
|
||||
number: 7745
|
||||
17
kubernetes/apps/immich/credentials.yaml
Normal file
17
kubernetes/apps/immich/credentials.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: immich-credentials
|
||||
namespace: media
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: immich-credentials
|
||||
data:
|
||||
- secretKey: DB_PASSWORD
|
||||
remoteRef:
|
||||
key: secret/immich
|
||||
property: DB_PASSWORD
|
||||
229
kubernetes/apps/immich/deployment.yaml
Normal file
229
kubernetes/apps/immich/deployment.yaml
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: immich-db-pvc
|
||||
namespace: media
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-db
|
||||
resources:
|
||||
requests:
|
||||
storage: 30Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: immich-library-pvc
|
||||
namespace: media
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 400Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: immich-postgres
|
||||
namespace: media
|
||||
spec:
|
||||
serviceName: immich-postgres
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: immich-postgres
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: immich-postgres
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: ghcr.io/immich-app/postgres:16-vectorchord1.1.1-pgvector0.8.5
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
value: immich
|
||||
- name: POSTGRES_USER
|
||||
value: postgres
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: immich-credentials
|
||||
key: DB_PASSWORD
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 2048Mi
|
||||
volumeMounts:
|
||||
- name: db-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumes:
|
||||
- name: db-data
|
||||
persistentVolumeClaim:
|
||||
claimName: immich-db-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: immich-postgres
|
||||
namespace: media
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: 5432
|
||||
selector:
|
||||
app: immich-postgres
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: immich-machine-learning
|
||||
namespace: media
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: immich-machine-learning
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: immich-machine-learning
|
||||
spec:
|
||||
containers:
|
||||
- name: ml
|
||||
image: ghcr.io/immich-app/immich-machine-learning:v3.1.0
|
||||
ports:
|
||||
- containerPort: 3003
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1024Mi
|
||||
limits:
|
||||
cpu: 3000m
|
||||
memory: 3072Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: immich-machine-learning
|
||||
namespace: media
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 3003
|
||||
targetPort: 3003
|
||||
selector:
|
||||
app: immich-machine-learning
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: immich-server
|
||||
namespace: media
|
||||
spec:
|
||||
serviceName: immich-server
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: immich-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: immich-server
|
||||
spec:
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
preference:
|
||||
matchExpressions:
|
||||
- key: feature.node.kubernetes.io/intel-qsv
|
||||
operator: In
|
||||
values: ["true"]
|
||||
containers:
|
||||
- name: server
|
||||
image: ghcr.io/immich-app/immich-server:v3.1.0
|
||||
ports:
|
||||
- containerPort: 2283
|
||||
env:
|
||||
- name: DB_HOSTNAME
|
||||
value: immich-postgres
|
||||
- name: DB_USERNAME
|
||||
value: postgres
|
||||
- name: DB_DATABASE_NAME
|
||||
value: immich
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: immich-credentials
|
||||
key: DB_PASSWORD
|
||||
- name: REDIS_HOSTNAME
|
||||
value: redis-core.databases.svc.cluster.local
|
||||
- name: IMMICH_MACHINE_LEARNING_URL
|
||||
value: http://immich-machine-learning:3003
|
||||
- name: IMMICH_MEDIA_LOCATION
|
||||
value: /usr/src/app/upload
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1024Mi
|
||||
limits:
|
||||
cpu: 3000m
|
||||
memory: 3072Mi
|
||||
volumeMounts:
|
||||
- name: library
|
||||
mountPath: /usr/src/app/upload
|
||||
volumes:
|
||||
- name: library
|
||||
persistentVolumeClaim:
|
||||
claimName: immich-library-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: immich-server
|
||||
namespace: media
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 2283
|
||||
targetPort: 2283
|
||||
selector:
|
||||
app: immich-server
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: immich
|
||||
namespace: media
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- immich.svo88.space
|
||||
secretName: immich-svo88-tls
|
||||
rules:
|
||||
- host: immich.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: immich-server
|
||||
port:
|
||||
number: 2283
|
||||
157
kubernetes/apps/invidious/deployment.yaml
Normal file
157
kubernetes/apps/invidious/deployment.yaml
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: invidious-credentials
|
||||
namespace: media
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: invidious-credentials
|
||||
data:
|
||||
- secretKey: DB_PASSWORD
|
||||
remoteRef:
|
||||
key: secret/invidious
|
||||
property: DB_PASSWORD
|
||||
- secretKey: HMAC_KEY
|
||||
remoteRef:
|
||||
key: secret/invidious
|
||||
property: HMAC_KEY
|
||||
- secretKey: COMPANION_KEY
|
||||
remoteRef:
|
||||
key: secret/invidious
|
||||
property: COMPANION_KEY
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: invidious
|
||||
namespace: media
|
||||
labels:
|
||||
app: invidious
|
||||
spec:
|
||||
serviceName: invidious
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: invidious
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: invidious
|
||||
spec:
|
||||
enableServiceLinks: false
|
||||
containers:
|
||||
- name: invidious
|
||||
image: quay.io/invidious/invidious:latest
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http
|
||||
env:
|
||||
- name: INVIDIOUS_PORT
|
||||
value: "3000"
|
||||
- name: PORT
|
||||
value: "3000"
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: invidious-credentials
|
||||
key: DB_PASSWORD
|
||||
- name: HMAC_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: invidious-credentials
|
||||
key: HMAC_KEY
|
||||
- name: COMPANION_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: invidious-credentials
|
||||
key: COMPANION_KEY
|
||||
- name: INVIDIOUS_CONFIG
|
||||
value: |
|
||||
db:
|
||||
dbname: invidious
|
||||
user: invidious
|
||||
password: $(DB_PASSWORD)
|
||||
host: postgres-core.databases.svc.cluster.local
|
||||
port: 5432
|
||||
check_tables: true
|
||||
domain: yt.svo88.space
|
||||
external_port: 443
|
||||
https_only: true
|
||||
port: 3000
|
||||
hmac_key: $(HMAC_KEY)
|
||||
invidious_companion:
|
||||
- private_url: "http://127.0.0.1:8282/companion"
|
||||
invidious_companion_key: $(COMPANION_KEY)
|
||||
default_user_preferences:
|
||||
dark_mode: true
|
||||
feed_menu: ["Subscriptions", "Playlists"]
|
||||
default_home: Subscriptions
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 1024Mi
|
||||
- name: companion
|
||||
image: quay.io/invidious/invidious-companion:latest
|
||||
ports:
|
||||
- containerPort: 8282
|
||||
env:
|
||||
- name: SERVER_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: invidious-credentials
|
||||
key: COMPANION_KEY
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: invidious
|
||||
namespace: media
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 3000
|
||||
targetPort: 3000
|
||||
name: http
|
||||
selector:
|
||||
app: invidious
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: invidious
|
||||
namespace: media
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- yt.svo88.space
|
||||
secretName: yt-svo88-tls
|
||||
rules:
|
||||
- host: yt.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: invidious
|
||||
port:
|
||||
number: 3000
|
||||
138
kubernetes/apps/jellyfin/deployment.yaml
Normal file
138
kubernetes/apps/jellyfin/deployment.yaml
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: nfs-media-pv
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Ti
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
mountOptions:
|
||||
- nfsvers=4.2
|
||||
nfs:
|
||||
server: 10.0.10.14
|
||||
path: /media
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: nfs-media-pvc
|
||||
namespace: media
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Ti
|
||||
volumeName: nfs-media-pv
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: jellyfin-config-pvc
|
||||
namespace: media
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: jellyfin
|
||||
namespace: media
|
||||
labels:
|
||||
app: jellyfin
|
||||
spec:
|
||||
serviceName: jellyfin
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: jellyfin
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: jellyfin
|
||||
spec:
|
||||
containers:
|
||||
- name: jellyfin
|
||||
image: jellyfin/jellyfin:latest
|
||||
ports:
|
||||
- containerPort: 8096
|
||||
name: http
|
||||
env:
|
||||
- name: JELLYFIN_PublishedServerUrl
|
||||
value: "https://jellyfin.svo88.space"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 4000m
|
||||
memory: 2048Mi
|
||||
volumeMounts:
|
||||
- name: config-storage
|
||||
mountPath: /config
|
||||
- name: config-storage
|
||||
mountPath: /cache
|
||||
subPath: cache
|
||||
- name: media-storage
|
||||
mountPath: /media
|
||||
- name: torrents-storage
|
||||
mountPath: /torrents
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: config-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: jellyfin-config-pvc
|
||||
- name: media-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: nfs-media-pvc
|
||||
- name: torrents-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: nfs-torrents-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: jellyfin
|
||||
namespace: media
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8096
|
||||
targetPort: 8096
|
||||
name: http
|
||||
selector:
|
||||
app: jellyfin
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: jellyfin
|
||||
namespace: media
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- jellyfin.svo88.space
|
||||
secretName: jellyfin-svo88-tls
|
||||
rules:
|
||||
- host: jellyfin.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: jellyfin
|
||||
port:
|
||||
number: 8096
|
||||
188
kubernetes/apps/karakeep/deployment.yaml
Normal file
188
kubernetes/apps/karakeep/deployment.yaml
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: karakeep-data-pvc
|
||||
namespace: tools
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 15Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: karakeep-meili-pvc
|
||||
namespace: tools
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: karakeep-credentials
|
||||
namespace: tools
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: karakeep-credentials
|
||||
data:
|
||||
- secretKey: NEXTAUTH_SECRET
|
||||
remoteRef:
|
||||
key: secret/karakeep
|
||||
property: NEXTAUTH_SECRET
|
||||
- secretKey: MEILI_MASTER_KEY
|
||||
remoteRef:
|
||||
key: secret/karakeep
|
||||
property: MEILI_MASTER_KEY
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: karakeep
|
||||
namespace: tools
|
||||
labels:
|
||||
app: karakeep
|
||||
spec:
|
||||
serviceName: karakeep
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: karakeep
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: karakeep
|
||||
spec:
|
||||
containers:
|
||||
- name: web
|
||||
image: ghcr.io/karakeep-app/karakeep:latest
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http
|
||||
env:
|
||||
- name: DATA_DIR
|
||||
value: "/data"
|
||||
- name: NEXTAUTH_URL
|
||||
value: "https://keep.svo88.space"
|
||||
- name: MEILI_ADDR
|
||||
value: "http://127.0.0.1:7700"
|
||||
- name: BROWSER_WEB_URL
|
||||
value: "http://127.0.0.1:9222"
|
||||
- name: DISABLE_SIGNUPS
|
||||
value: "false"
|
||||
- name: CRAWLER_DOWNLOAD_BANNER_IMAGE
|
||||
value: "true"
|
||||
- name: NEXTAUTH_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: karakeep-credentials
|
||||
key: NEXTAUTH_SECRET
|
||||
- name: MEILI_MASTER_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: karakeep-credentials
|
||||
key: MEILI_MASTER_KEY
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 1024Mi
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
- name: meilisearch
|
||||
image: getmeili/meilisearch:v1.11
|
||||
ports:
|
||||
- containerPort: 7700
|
||||
name: meili
|
||||
env:
|
||||
- name: MEILI_NO_ANALYTICS
|
||||
value: "true"
|
||||
- name: MEILI_MASTER_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: karakeep-credentials
|
||||
key: MEILI_MASTER_KEY
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
volumeMounts:
|
||||
- name: meili-data
|
||||
mountPath: /meili_data
|
||||
- name: chrome
|
||||
image: ghcr.io/karakeep-app/karakeep-chrome:release
|
||||
ports:
|
||||
- containerPort: 9222
|
||||
name: cdp
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1500m
|
||||
memory: 1024Mi
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: karakeep-data-pvc
|
||||
- name: meili-data
|
||||
persistentVolumeClaim:
|
||||
claimName: karakeep-meili-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: karakeep
|
||||
namespace: tools
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 3000
|
||||
targetPort: 3000
|
||||
name: http
|
||||
selector:
|
||||
app: karakeep
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: karakeep
|
||||
namespace: tools
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- keep.svo88.space
|
||||
secretName: keep-svo88-tls
|
||||
rules:
|
||||
- host: keep.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: karakeep
|
||||
port:
|
||||
number: 3000
|
||||
81
kubernetes/apps/kiwix/deployment.yaml
Normal file
81
kubernetes/apps/kiwix/deployment.yaml
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: nfs-kiwix-pv
|
||||
spec:
|
||||
capacity:
|
||||
storage: 200Gi
|
||||
accessModes:
|
||||
- ReadOnlyMany
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
mountOptions:
|
||||
- nfsvers=4.2
|
||||
nfs:
|
||||
server: 10.0.10.14
|
||||
path: /media
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: nfs-kiwix-pvc
|
||||
namespace: media
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadOnlyMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 200Gi
|
||||
volumeName: nfs-kiwix-pv
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: kiwix-reader
|
||||
namespace: media
|
||||
spec:
|
||||
serviceName: kiwix-reader
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kiwix-reader
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kiwix-reader
|
||||
spec:
|
||||
containers:
|
||||
- name: kiwix-reader
|
||||
image: ghcr.io/kiwix/kiwix-serve:latest
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
if ls /data/*.zim 1> /dev/null 2>&1; then
|
||||
exec kiwix-serve --port 8080 /data/*.zim
|
||||
else
|
||||
echo "No .zim archives found in /data. Waiting for files..."
|
||||
sleep infinity
|
||||
fi
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
volumeMounts:
|
||||
- name: kiwix-storage
|
||||
mountPath: /data
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: kiwix-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: nfs-kiwix-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kiwix-reader
|
||||
namespace: media
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: kiwix-reader
|
||||
34
kubernetes/apps/kustomization.yaml
Normal file
34
kubernetes/apps/kustomization.yaml
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- authentik/credentials.yaml
|
||||
- authentik/deployment.yaml
|
||||
- core-db/core-db.yaml
|
||||
- dashboard/deployment.yaml
|
||||
- homebox/deployment.yaml
|
||||
- immich/credentials.yaml
|
||||
- immich/deployment.yaml
|
||||
- invidious/deployment.yaml
|
||||
- jellyfin/deployment.yaml
|
||||
- karakeep/deployment.yaml
|
||||
- kiwix/deployment.yaml
|
||||
- metube/deployment.yaml
|
||||
- netbox/credentials.yaml
|
||||
- netbox/deployment.yaml
|
||||
- opencloud/deployment.yaml
|
||||
- paperless/credentials.yaml
|
||||
- paperless/deployment.yaml
|
||||
- printstash/credentials.yaml
|
||||
- printstash/deployment.yaml
|
||||
- qbittorrent/deployment.yaml
|
||||
- searxng/deployment.yaml
|
||||
- spoolman/deployment.yaml
|
||||
- sure-finance/deployment.yaml
|
||||
- tier0/dns.yaml
|
||||
- tier0/forgejo.yaml
|
||||
- tier0/pve.yaml
|
||||
- tier0/vault.yaml
|
||||
- tier0/zot.yaml
|
||||
- trilium/deployment.yaml
|
||||
- vaultwarden/credentials.yaml
|
||||
- vaultwarden/deployment.yaml
|
||||
86
kubernetes/apps/metube/deployment.yaml
Normal file
86
kubernetes/apps/metube/deployment.yaml
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: metube
|
||||
namespace: media
|
||||
labels:
|
||||
app: metube
|
||||
spec:
|
||||
serviceName: metube
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: metube
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: metube
|
||||
spec:
|
||||
containers:
|
||||
- name: metube
|
||||
image: ghcr.io/alexta69/metube:latest
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
name: http
|
||||
env:
|
||||
- name: OUTPUT_TEMPLATE
|
||||
value: "%(playlist_title)s/%(title)s.%(ext)s"
|
||||
- name: DOWNLOAD_DIR
|
||||
value: "/downloads"
|
||||
- name: STATE_DIR
|
||||
value: "/downloads/.metube"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 512Mi
|
||||
volumeMounts:
|
||||
- name: media-storage
|
||||
mountPath: /downloads
|
||||
volumes:
|
||||
- name: media-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: nfs-media-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: metube
|
||||
namespace: media
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8081
|
||||
targetPort: 8081
|
||||
name: http
|
||||
selector:
|
||||
app: metube
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: metube
|
||||
namespace: media
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- metube.svo88.space
|
||||
secretName: metube-svo88-tls
|
||||
rules:
|
||||
- host: metube.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: metube
|
||||
port:
|
||||
number: 8081
|
||||
21
kubernetes/apps/netbox/credentials.yaml
Normal file
21
kubernetes/apps/netbox/credentials.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: netbox-credentials
|
||||
namespace: infra
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: netbox-credentials
|
||||
data:
|
||||
- secretKey: DB_PASSWORD
|
||||
remoteRef:
|
||||
key: secret/netbox
|
||||
property: DB_PASSWORD
|
||||
- secretKey: SECRET_KEY
|
||||
remoteRef:
|
||||
key: secret/netbox
|
||||
property: SECRET_KEY
|
||||
107
kubernetes/apps/netbox/deployment.yaml
Normal file
107
kubernetes/apps/netbox/deployment.yaml
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: infra
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: netbox-media-pvc
|
||||
namespace: infra
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: netbox
|
||||
namespace: infra
|
||||
spec:
|
||||
serviceName: netbox
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: netbox
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: netbox
|
||||
spec:
|
||||
containers:
|
||||
- name: netbox
|
||||
image: netboxcommunity/netbox:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: DB_HOST
|
||||
value: postgres-core.databases.svc.cluster.local
|
||||
- name: DB_NAME
|
||||
value: netbox
|
||||
- name: DB_USER
|
||||
value: netbox
|
||||
- name: REDIS_HOST
|
||||
value: redis-core.databases.svc.cluster.local
|
||||
- name: REDIS_CACHE_HOST
|
||||
value: redis-core.databases.svc.cluster.local
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: netbox-credentials
|
||||
key: DB_PASSWORD
|
||||
- name: SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: netbox-credentials
|
||||
key: SECRET_KEY
|
||||
volumeMounts:
|
||||
- name: netbox-media
|
||||
mountPath: /opt/netbox/netbox/media
|
||||
volumes:
|
||||
- name: netbox-media
|
||||
persistentVolumeClaim:
|
||||
claimName: netbox-media-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: netbox
|
||||
namespace: infra
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: netbox
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: netbox
|
||||
namespace: infra
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- netbox.svo88.space
|
||||
secretName: netbox-svo88-tls
|
||||
rules:
|
||||
- host: netbox.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: netbox
|
||||
port:
|
||||
number: 8080
|
||||
158
kubernetes/apps/opencloud/deployment.yaml
Normal file
158
kubernetes/apps/opencloud/deployment.yaml
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: storage
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: opencloud-csp
|
||||
namespace: storage
|
||||
data:
|
||||
csp.yaml: |
|
||||
directives:
|
||||
connect-src:
|
||||
- "'self'"
|
||||
- "blob:"
|
||||
- "https://auth.svo88.space"
|
||||
- "https://raw.githubusercontent.com/opencloud-eu/awesome-apps/"
|
||||
- "https://update.opencloud.eu/"
|
||||
frame-src:
|
||||
- "'self'"
|
||||
- "https://auth.svo88.space"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: opencloud-data-pvc
|
||||
namespace: storage
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 800Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: opencloud
|
||||
namespace: storage
|
||||
spec:
|
||||
serviceName: opencloud
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: opencloud
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: opencloud
|
||||
spec:
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: opencloud
|
||||
image: opencloudeu/opencloud-rolling:8.0.1
|
||||
command: ["/bin/sh", "-c", "opencloud init || true; exec opencloud server"]
|
||||
ports:
|
||||
- containerPort: 9200
|
||||
env:
|
||||
- name: OC_URL
|
||||
value: "https://opencloud.svo88.space"
|
||||
- name: OC_INSECURE
|
||||
value: "false"
|
||||
- name: PROXY_TLS
|
||||
value: "false"
|
||||
- name: PROXY_HTTP_ADDR
|
||||
value: "0.0.0.0:9200"
|
||||
- name: PROXY_CSP_CONFIG_FILE_LOCATION
|
||||
value: "/etc/opencloud-config/csp.yaml"
|
||||
- name: OC_OIDC_ISSUER
|
||||
value: "https://auth.svo88.space/application/o/opencloud/"
|
||||
- name: WEB_OIDC_CLIENT_ID
|
||||
value: "web"
|
||||
- name: WEBFINGER_ANDROID_OIDC_CLIENT_ID
|
||||
value: "web"
|
||||
- name: WEBFINGER_ANDROID_OIDC_CLIENT_SCOPES
|
||||
value: "openid profile email offline_access"
|
||||
- name: PROXY_OIDC_REWRITE_WELLKNOWN
|
||||
value: "true"
|
||||
- name: PROXY_AUTOPROVISION_ACCOUNTS
|
||||
value: "true"
|
||||
- name: PROXY_USER_OIDC_CLAIM
|
||||
value: "preferred_username"
|
||||
- name: OC_EXCLUDE_RUN_SERVICES
|
||||
value: "idp"
|
||||
- name: PROXY_TRANSPORT_READ_TIMEOUT
|
||||
value: "3600s"
|
||||
- name: PROXY_TRANSPORT_WRITE_TIMEOUT
|
||||
value: "3600s"
|
||||
- name: STORAGE_USERS_DATA_SERVER_READ_TIMEOUT
|
||||
value: "3600s"
|
||||
- name: STORAGE_USERS_DATA_SERVER_WRITE_TIMEOUT
|
||||
value: "3600s"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1024Mi
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 2048Mi
|
||||
volumeMounts:
|
||||
- name: opencloud-data
|
||||
mountPath: /var/lib/opencloud
|
||||
subPath: data
|
||||
- name: opencloud-data
|
||||
mountPath: /etc/opencloud
|
||||
subPath: config
|
||||
- name: opencloud-csp-config
|
||||
mountPath: /etc/opencloud-config/csp.yaml
|
||||
subPath: csp.yaml
|
||||
volumes:
|
||||
- name: opencloud-data
|
||||
persistentVolumeClaim:
|
||||
claimName: opencloud-data-pvc
|
||||
- name: opencloud-csp-config
|
||||
configMap:
|
||||
name: opencloud-csp
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: opencloud
|
||||
namespace: storage
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 9200
|
||||
targetPort: 9200
|
||||
selector:
|
||||
app: opencloud
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: opencloud
|
||||
namespace: storage
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- opencloud.svo88.space
|
||||
secretName: opencloud-svo88-tls
|
||||
rules:
|
||||
- host: opencloud.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: opencloud
|
||||
port:
|
||||
number: 9200
|
||||
21
kubernetes/apps/paperless/credentials.yaml
Normal file
21
kubernetes/apps/paperless/credentials.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: paperless-credentials
|
||||
namespace: documents
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: paperless-credentials
|
||||
data:
|
||||
- secretKey: PAPERLESS_DBPASS
|
||||
remoteRef:
|
||||
key: secret/paperless
|
||||
property: PAPERLESS_DBPASS
|
||||
- secretKey: PAPERLESS_SECRET_KEY
|
||||
remoteRef:
|
||||
key: secret/paperless
|
||||
property: PAPERLESS_SECRET_KEY
|
||||
135
kubernetes/apps/paperless/deployment.yaml
Normal file
135
kubernetes/apps/paperless/deployment.yaml
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: documents
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: paperless-data-pvc
|
||||
namespace: documents
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 30Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: paperless
|
||||
namespace: documents
|
||||
spec:
|
||||
serviceName: paperless
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: paperless
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: paperless
|
||||
spec:
|
||||
enableServiceLinks: false
|
||||
initContainers:
|
||||
- name: clear-migration-lock
|
||||
image: busybox:latest
|
||||
command: ["sh", "-c", "rm -f /data/migration_lock"]
|
||||
volumeMounts:
|
||||
- name: paperless-data
|
||||
mountPath: /data
|
||||
subPath: data
|
||||
containers:
|
||||
- name: paperless-ngx
|
||||
image: ghcr.io/paperless-ngx/paperless-ngx:latest
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
env:
|
||||
- name: PAPERLESS_PORT
|
||||
value: "8000"
|
||||
- name: PAPERLESS_URL
|
||||
value: "https://docs.svo88.space"
|
||||
- name: PAPERLESS_CSRF_TRUSTED_ORIGINS
|
||||
value: "https://docs.svo88.space"
|
||||
- name: PAPERLESS_TRUSTED_PROXIES
|
||||
value: "10.0.0.0/8,10.244.0.0/16"
|
||||
- name: PAPERLESS_REDIS
|
||||
value: redis://redis-core.databases.svc.cluster.local:6379
|
||||
- name: PAPERLESS_DBENGINE
|
||||
value: postgresql
|
||||
- name: PAPERLESS_DBHOST
|
||||
value: postgres-core.databases.svc.cluster.local
|
||||
- name: PAPERLESS_DBNAME
|
||||
value: paperless
|
||||
- name: PAPERLESS_DBUSER
|
||||
value: paperless
|
||||
- name: PAPERLESS_OCR_LANGUAGES
|
||||
value: "rus"
|
||||
- name: PAPERLESS_OCR_LANGUAGE
|
||||
value: rus+eng
|
||||
- name: PAPERLESS_DBPASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: paperless-credentials
|
||||
key: PAPERLESS_DBPASS
|
||||
- name: PAPERLESS_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: paperless-credentials
|
||||
key: PAPERLESS_SECRET_KEY
|
||||
volumeMounts:
|
||||
- name: paperless-data
|
||||
mountPath: /usr/src/paperless/data
|
||||
subPath: data
|
||||
- name: paperless-data
|
||||
mountPath: /usr/src/paperless/media
|
||||
subPath: media
|
||||
- name: paperless-data
|
||||
mountPath: /usr/src/paperless/export
|
||||
subPath: export
|
||||
volumes:
|
||||
- name: paperless-data
|
||||
persistentVolumeClaim:
|
||||
claimName: paperless-data-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: paperless
|
||||
namespace: documents
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8000
|
||||
targetPort: 8000
|
||||
selector:
|
||||
app: paperless
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: paperless
|
||||
namespace: documents
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- paperless.svo88.space
|
||||
secretName: paperless-svo88-tls
|
||||
rules:
|
||||
- host: paperless.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: paperless
|
||||
port:
|
||||
number: 8000
|
||||
17
kubernetes/apps/printstash/credentials.yaml
Normal file
17
kubernetes/apps/printstash/credentials.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: printstash-credentials
|
||||
namespace: tools
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: printstash-credentials
|
||||
data:
|
||||
- secretKey: DB_PASSWORD
|
||||
remoteRef:
|
||||
key: secret/printstash
|
||||
property: DB_PASSWORD
|
||||
124
kubernetes/apps/printstash/deployment.yaml
Normal file
124
kubernetes/apps/printstash/deployment.yaml
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: tools
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: printstash-models-pv
|
||||
spec:
|
||||
capacity:
|
||||
storage: 100Gi
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
mountOptions:
|
||||
- nfsvers=4.2
|
||||
nfs:
|
||||
server: 10.0.10.14
|
||||
path: /models
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: printstash-models-pvc
|
||||
namespace: tools
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 100Gi
|
||||
volumeName: printstash-models-pv
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: printstash
|
||||
namespace: tools
|
||||
spec:
|
||||
serviceName: printstash
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: printstash
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: printstash
|
||||
spec:
|
||||
containers:
|
||||
- name: printstash
|
||||
image: ghcr.io/xiao-villamor/printstash:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: VAULT_SETUP_MODE
|
||||
value: "trusted_network"
|
||||
- name: VAULT_SETUP_ALLOWED_HOSTS
|
||||
value: "printstash.svo88.space"
|
||||
- name: VAULT_SESSION_COOKIE_SECURE
|
||||
value: "true"
|
||||
- name: FORWARDED_ALLOW_IPS
|
||||
value: "*"
|
||||
- name: DB_HOST
|
||||
value: postgres-core.databases.svc.cluster.local
|
||||
- name: DB_PORT
|
||||
value: "5432"
|
||||
- name: DB_NAME
|
||||
value: printstash
|
||||
- name: DB_USER
|
||||
value: printstash
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: printstash-credentials
|
||||
key: DB_PASSWORD
|
||||
volumeMounts:
|
||||
- name: models-storage
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: models-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: printstash-models-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: printstash
|
||||
namespace: tools
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 3000
|
||||
selector:
|
||||
app: printstash
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: printstash
|
||||
namespace: tools
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- printstash.svo88.space
|
||||
secretName: printstash-svo88-tls
|
||||
rules:
|
||||
- host: printstash.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: printstash
|
||||
port:
|
||||
number: 8080
|
||||
102
kubernetes/apps/qbittorrent/deployment.yaml
Normal file
102
kubernetes/apps/qbittorrent/deployment.yaml
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: media
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: nfs-torrents-pv
|
||||
spec:
|
||||
capacity:
|
||||
storage: 500Gi
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
mountOptions:
|
||||
- nfsvers=4.2
|
||||
nfs:
|
||||
server: 10.0.10.14
|
||||
path: /torrents
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: nfs-torrents-pvc
|
||||
namespace: media
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 500Gi
|
||||
volumeName: nfs-torrents-pv
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: qbittorrent
|
||||
namespace: media
|
||||
spec:
|
||||
serviceName: qbittorrent
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: qbittorrent
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: qbittorrent
|
||||
spec:
|
||||
containers:
|
||||
- name: qbittorrent
|
||||
image: lscr.io/linuxserver/qbittorrent:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: webui
|
||||
- containerPort: 6881
|
||||
protocol: TCP
|
||||
name: torrent-tcp
|
||||
- containerPort: 6881
|
||||
protocol: UDP
|
||||
name: torrent-udp
|
||||
env:
|
||||
- name: PUID
|
||||
value: "1000"
|
||||
- name: PGID
|
||||
value: "1000"
|
||||
- name: WEBUI_PORT
|
||||
value: "8080"
|
||||
volumeMounts:
|
||||
- name: torrents-storage
|
||||
mountPath: /downloads
|
||||
subPath: downloads
|
||||
- name: torrents-storage
|
||||
mountPath: /config
|
||||
subPath: config
|
||||
volumes:
|
||||
- name: torrents-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: nfs-torrents-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: qbittorrent
|
||||
namespace: media
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
name: webui
|
||||
- port: 6881
|
||||
targetPort: 6881
|
||||
protocol: TCP
|
||||
name: torrent-tcp
|
||||
- port: 6881
|
||||
targetPort: 6881
|
||||
protocol: UDP
|
||||
name: torrent-udp
|
||||
selector:
|
||||
app: qbittorrent
|
||||
89
kubernetes/apps/searxng/deployment.yaml
Normal file
89
kubernetes/apps/searxng/deployment.yaml
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: searxng-credentials
|
||||
namespace: tools
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: searxng-credentials
|
||||
data:
|
||||
- secretKey: SEARXNG_SECRET
|
||||
remoteRef:
|
||||
key: secret/searxng
|
||||
property: SEARXNG_SECRET
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: searxng
|
||||
namespace: tools
|
||||
spec:
|
||||
serviceName: searxng
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: searxng
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: searxng
|
||||
spec:
|
||||
containers:
|
||||
- name: searxng
|
||||
image: searxng/searxng:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
env:
|
||||
- name: INSTANCE_NAME
|
||||
value: "Sovereign Search"
|
||||
- name: BASE_URL
|
||||
value: "https://search.svo88.space"
|
||||
- name: SEARXNG_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: searxng-credentials
|
||||
key: SEARXNG_SECRET
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: searxng
|
||||
namespace: tools
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: searxng
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: searxng
|
||||
namespace: tools
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- search.svo88.space
|
||||
secretName: search-svo88-tls
|
||||
rules:
|
||||
- host: search.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: searxng
|
||||
port:
|
||||
number: 8080
|
||||
83
kubernetes/apps/spoolman/deployment.yaml
Normal file
83
kubernetes/apps/spoolman/deployment.yaml
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: spoolman-data-pvc
|
||||
namespace: tools
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: spoolman
|
||||
namespace: tools
|
||||
spec:
|
||||
serviceName: spoolman
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spoolman
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spoolman
|
||||
spec:
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: spoolman
|
||||
image: ghcr.io/donkie/spoolman:latest
|
||||
ports:
|
||||
- containerPort: 7912
|
||||
volumeMounts:
|
||||
- name: spoolman-data
|
||||
mountPath: /home/app/.local/share/spoolman
|
||||
volumes:
|
||||
- name: spoolman-data
|
||||
persistentVolumeClaim:
|
||||
claimName: spoolman-data-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: spoolman
|
||||
namespace: tools
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 7912
|
||||
targetPort: 8000
|
||||
selector:
|
||||
app: spoolman
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: spoolman
|
||||
namespace: tools
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- spoolman.svo88.space
|
||||
secretName: spoolman-svo88-tls
|
||||
rules:
|
||||
- host: spoolman.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: spoolman
|
||||
port:
|
||||
number: 7912
|
||||
108
kubernetes/apps/sure-finance/deployment.yaml
Normal file
108
kubernetes/apps/sure-finance/deployment.yaml
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: sure-finance
|
||||
namespace: tools
|
||||
spec:
|
||||
serviceName: sure-finance
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: sure-finance
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: sure-finance
|
||||
spec:
|
||||
containers:
|
||||
- name: sure-finance
|
||||
image: ghcr.io/we-promise/sure:latest
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
env:
|
||||
- name: SELF_HOSTED
|
||||
value: "true"
|
||||
- name: SECRET_KEY_BASE
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: sure-credentials
|
||||
key: SECRET_KEY_BASE
|
||||
- name: DB_HOST
|
||||
value: postgres-core.databases.svc.cluster.local
|
||||
- name: POSTGRES_HOST
|
||||
value: postgres-core.databases.svc.cluster.local
|
||||
- name: POSTGRES_PORT
|
||||
value: "5432"
|
||||
- name: POSTGRES_DB
|
||||
value: sure_finance
|
||||
- name: POSTGRES_USER
|
||||
value: sure
|
||||
- name: REDIS_URL
|
||||
value: redis://redis-core.databases.svc.cluster.local:6379/1
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: sure-credentials
|
||||
key: DB_PASSWORD
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: sure-finance
|
||||
namespace: tools
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 3000
|
||||
targetPort: 3000
|
||||
selector:
|
||||
app: sure-finance
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: sure-credentials
|
||||
namespace: tools
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: sure-credentials
|
||||
data:
|
||||
- secretKey: DB_PASSWORD
|
||||
remoteRef:
|
||||
key: secret/sure
|
||||
property: DB_PASSWORD
|
||||
- secretKey: SECRET_KEY_BASE
|
||||
remoteRef:
|
||||
key: secret/sure
|
||||
property: SECRET_KEY_BASE
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: sure-finance
|
||||
namespace: tools
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- finance.svo88.space
|
||||
secretName: finance-svo88-tls
|
||||
rules:
|
||||
- host: finance.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: sure-finance
|
||||
port:
|
||||
number: 3000
|
||||
49
kubernetes/apps/tier0/dns.yaml
Normal file
49
kubernetes/apps/tier0/dns.yaml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: technitium-dns
|
||||
namespace: infra
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 5380
|
||||
targetPort: 5380
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: technitium-dns
|
||||
namespace: infra
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.0.10.11
|
||||
ports:
|
||||
- name: http
|
||||
port: 5380
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: technitium-dns
|
||||
namespace: infra
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-local-only@kubernetescrd,traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- dns.svo88.space
|
||||
secretName: dns-svo88-tls
|
||||
rules:
|
||||
- host: dns.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: technitium-dns
|
||||
port:
|
||||
number: 5380
|
||||
48
kubernetes/apps/tier0/forgejo.yaml
Normal file
48
kubernetes/apps/tier0/forgejo.yaml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: forgejo-git
|
||||
namespace: infra
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 3000
|
||||
targetPort: 3000
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: forgejo-git
|
||||
namespace: infra
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.0.10.13
|
||||
ports:
|
||||
- name: http
|
||||
port: 3000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: forgejo-git
|
||||
namespace: infra
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- git.svo88.space
|
||||
secretName: git-svo88-tls
|
||||
rules:
|
||||
- host: git.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: forgejo-git
|
||||
port:
|
||||
number: 3000
|
||||
52
kubernetes/apps/tier0/pve.yaml
Normal file
52
kubernetes/apps/tier0/pve.yaml
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: proxmox-ve
|
||||
namespace: infra
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/service.serversscheme: https
|
||||
traefik.ingress.kubernetes.io/service.serverstransport: traefik-pve-transport@kubernetescrd
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8006
|
||||
targetPort: 8006
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: proxmox-ve
|
||||
namespace: infra
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 192.168.1.177
|
||||
ports:
|
||||
- name: https
|
||||
port: 8006
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: proxmox-ve
|
||||
namespace: infra
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-local-only@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- pve.svo88.space
|
||||
secretName: pve-svo88-tls
|
||||
rules:
|
||||
- host: pve.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: proxmox-ve
|
||||
port:
|
||||
number: 8006
|
||||
49
kubernetes/apps/tier0/vault.yaml
Normal file
49
kubernetes/apps/tier0/vault.yaml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: openbao-vault
|
||||
namespace: infra
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8200
|
||||
targetPort: 8200
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: openbao-vault
|
||||
namespace: infra
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.0.10.12
|
||||
ports:
|
||||
- name: http
|
||||
port: 8200
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: openbao-vault
|
||||
namespace: infra
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-local-only@kubernetescrd,traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- vault.svo88.space
|
||||
secretName: vault-svo88-tls
|
||||
rules:
|
||||
- host: vault.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: openbao-vault
|
||||
port:
|
||||
number: 8200
|
||||
49
kubernetes/apps/tier0/zot.yaml
Normal file
49
kubernetes/apps/tier0/zot.yaml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: zot-registry
|
||||
namespace: infra
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 5000
|
||||
targetPort: 5000
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: zot-registry
|
||||
namespace: infra
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.0.10.15
|
||||
ports:
|
||||
- name: http
|
||||
port: 5000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: zot-registry
|
||||
namespace: infra
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: traefik-local-only@kubernetescrd,traefik-authentik@kubernetescrd
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- zot.svo88.space
|
||||
secretName: zot-svo88-tls
|
||||
rules:
|
||||
- host: zot.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: zot-registry
|
||||
port:
|
||||
number: 5000
|
||||
99
kubernetes/apps/trilium/deployment.yaml
Normal file
99
kubernetes/apps/trilium/deployment.yaml
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: trilium-data-pvc
|
||||
namespace: documents
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: trilium
|
||||
namespace: documents
|
||||
labels:
|
||||
app: trilium
|
||||
spec:
|
||||
serviceName: trilium
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: trilium
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: trilium
|
||||
spec:
|
||||
enableServiceLinks: false
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: trilium
|
||||
image: ghcr.io/triliumnext/trilium:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
env:
|
||||
- name: TRILIUM_DATA_DIR
|
||||
value: "/home/node/trilium-data"
|
||||
- name: TRILIUM_PORT
|
||||
value: "8080"
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 1500m
|
||||
memory: 512Mi
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /home/node/trilium-data
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: trilium-data-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: trilium
|
||||
namespace: documents
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
name: http
|
||||
selector:
|
||||
app: trilium
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: trilium
|
||||
namespace: documents
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- trilium.svo88.space
|
||||
secretName: trilium-svo88-tls
|
||||
rules:
|
||||
- host: trilium.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: trilium
|
||||
port:
|
||||
number: 8080
|
||||
17
kubernetes/apps/vaultwarden/credentials.yaml
Normal file
17
kubernetes/apps/vaultwarden/credentials.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: vaultwarden-credentials
|
||||
namespace: security
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: vaultwarden-credentials
|
||||
data:
|
||||
- secretKey: ADMIN_TOKEN
|
||||
remoteRef:
|
||||
key: secret/vaultwarden
|
||||
property: ADMIN_TOKEN
|
||||
103
kubernetes/apps/vaultwarden/deployment.yaml
Normal file
103
kubernetes/apps/vaultwarden/deployment.yaml
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: security
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: vaultwarden-data-pvc
|
||||
namespace: security
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: vaultwarden
|
||||
namespace: security
|
||||
spec:
|
||||
serviceName: vaultwarden
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: vaultwarden
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: vaultwarden
|
||||
spec:
|
||||
containers:
|
||||
- name: vaultwarden
|
||||
image: vaultwarden/server:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
env:
|
||||
- name: SIGNUPS_ALLOWED
|
||||
value: "false"
|
||||
- name: INVITATIONS_ALLOWED
|
||||
value: "false"
|
||||
- name: SHOW_PASSWORD_HINT
|
||||
value: "false"
|
||||
- name: ADMIN_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: vaultwarden-credentials
|
||||
key: ADMIN_TOKEN
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
volumeMounts:
|
||||
- name: vaultwarden-data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: vaultwarden-data
|
||||
persistentVolumeClaim:
|
||||
claimName: vaultwarden-data-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: vaultwarden
|
||||
namespace: security
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: vaultwarden
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: vaultwarden
|
||||
namespace: security
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- vw.svo88.space
|
||||
secretName: vw-svo88-tls
|
||||
rules:
|
||||
- host: vw.svo88.space
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: vaultwarden
|
||||
port:
|
||||
number: 80
|
||||
42
kubernetes/bootstrap/sync.yaml
Normal file
42
kubernetes/bootstrap/sync.yaml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: atlas-repo
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 1m
|
||||
url: http://10.0.10.13:3000/atlas/atlas.git
|
||||
ref:
|
||||
branch: master
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: infra-sync
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
path: ./kubernetes/infrastructure
|
||||
prune: true
|
||||
wait: true
|
||||
timeout: 5m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: atlas-repo
|
||||
---
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: apps-sync
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
path: ./kubernetes/apps
|
||||
prune: true
|
||||
wait: false
|
||||
timeout: 10m
|
||||
dependsOn:
|
||||
- name: infra-sync
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: atlas-repo
|
||||
20
kubernetes/infrastructure/cert-manager/cluster-issuer.yaml
Normal file
20
kubernetes/infrastructure/cert-manager/cluster-issuer.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-prod
|
||||
spec:
|
||||
acme:
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
email: atlas@svo88.space
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-prod-account-key
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
ingressClassName: traefik
|
||||
ingressTemplate:
|
||||
metadata:
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: web,websecure
|
||||
---
|
||||
60
kubernetes/infrastructure/cert-manager/helm-release.yaml
Normal file
60
kubernetes/infrastructure/cert-manager/helm-release.yaml
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: cert-manager
|
||||
---
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: cert-manager
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
interval: 24h
|
||||
url: https://charts.jetstack.io
|
||||
---
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: cert-manager
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
interval: 1h
|
||||
chart:
|
||||
spec:
|
||||
chart: cert-manager
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cert-manager
|
||||
install:
|
||||
createNamespace: true
|
||||
crds: CreateReplace
|
||||
upgrade:
|
||||
crds: CreateReplace
|
||||
values:
|
||||
installCRDs: true
|
||||
extraArgs:
|
||||
- --dns01-recursive-nameservers-only
|
||||
- --dns01-recursive-nameservers=10.0.10.11:53
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
webhook:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
cainjector:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
70
kubernetes/infrastructure/cilium/helm-release.yaml
Normal file
70
kubernetes/infrastructure/cilium/helm-release.yaml
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: cilium
|
||||
namespace: kube-system
|
||||
spec:
|
||||
interval: 24h
|
||||
url: https://helm.cilium.io/
|
||||
---
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: cilium
|
||||
namespace: kube-system
|
||||
spec:
|
||||
interval: 1h
|
||||
chart:
|
||||
spec:
|
||||
chart: cilium
|
||||
version: "1.15.5"
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: cilium
|
||||
install:
|
||||
crds: CreateReplace
|
||||
upgrade:
|
||||
crds: CreateReplace
|
||||
values:
|
||||
k8sServiceHost: 127.0.0.1
|
||||
k8sServicePort: 7445
|
||||
kubeProxyReplacement: true
|
||||
l2announcements:
|
||||
enabled: true
|
||||
devices: "ens+"
|
||||
ipam:
|
||||
mode: kubernetes
|
||||
cgroup:
|
||||
autoMount:
|
||||
enabled: false
|
||||
hostRoot: /sys/fs/cgroup
|
||||
securityContext:
|
||||
capabilities:
|
||||
ciliumAgent:
|
||||
- CHOWN
|
||||
- KILL
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
- IPC_LOCK
|
||||
- SYS_ADMIN
|
||||
- SYS_RESOURCE
|
||||
- DAC_OVERRIDE
|
||||
- FOWNER
|
||||
- SETGID
|
||||
- SETUID
|
||||
cleanCiliumState:
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
- SYS_RESOURCE
|
||||
image:
|
||||
repository: quay.io/cilium/cilium
|
||||
useDigest: false
|
||||
operator:
|
||||
image:
|
||||
repository: quay.io/cilium/operator
|
||||
useDigest: false
|
||||
envoy:
|
||||
image:
|
||||
repository: quay.io/cilium/cilium-envoy
|
||||
useDigest: false
|
||||
---
|
||||
20
kubernetes/infrastructure/cilium/l2-policy.yaml
Normal file
20
kubernetes/infrastructure/cilium/l2-policy.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: cilium.io/v2alpha1
|
||||
kind: CiliumLoadBalancerIPPool
|
||||
metadata:
|
||||
name: lan-ingress-pool
|
||||
spec:
|
||||
blocks:
|
||||
- cidr: 10.0.30.200/32
|
||||
---
|
||||
apiVersion: cilium.io/v2alpha1
|
||||
kind: CiliumL2AnnouncementPolicy
|
||||
metadata:
|
||||
name: lan-fastpath-announcement
|
||||
spec:
|
||||
nodeSelector:
|
||||
matchExpressions:
|
||||
- key: node-role.kubernetes.io/control-plane
|
||||
operator: DoesNotExist
|
||||
interfaces:
|
||||
- ens19
|
||||
loadBalancerIPs: true
|
||||
40
kubernetes/infrastructure/cilium/values.yaml
Normal file
40
kubernetes/infrastructure/cilium/values.yaml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
k8sServiceHost: 127.0.0.1
|
||||
k8sServicePort: 7445
|
||||
kubeProxyReplacement: true
|
||||
l2announcements:
|
||||
enabled: true
|
||||
ipam:
|
||||
mode: kubernetes
|
||||
cgroup:
|
||||
autoMount:
|
||||
enabled: false
|
||||
hostRoot: /sys/fs/cgroup
|
||||
securityContext:
|
||||
capabilities:
|
||||
ciliumAgent:
|
||||
- CHOWN
|
||||
- KILL
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
- IPC_LOCK
|
||||
- SYS_ADMIN
|
||||
- SYS_RESOURCE
|
||||
- DAC_OVERRIDE
|
||||
- FOWNER
|
||||
- SETGID
|
||||
- SETUID
|
||||
cleanCiliumState:
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
- SYS_RESOURCE
|
||||
image:
|
||||
repository: quay.io/cilium/cilium
|
||||
useDigest: false
|
||||
operator:
|
||||
image:
|
||||
repository: quay.io/cilium/operator
|
||||
useDigest: false
|
||||
envoy:
|
||||
image:
|
||||
repository: quay.io/cilium/cilium-envoy
|
||||
useDigest: false
|
||||
31
kubernetes/infrastructure/external-secrets/helm-release.yaml
Normal file
31
kubernetes/infrastructure/external-secrets/helm-release.yaml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: external-secrets
|
||||
namespace: external-secrets
|
||||
spec:
|
||||
interval: 24h
|
||||
url: https://charts.external-secrets.io
|
||||
---
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: external-secrets
|
||||
namespace: external-secrets
|
||||
spec:
|
||||
interval: 1h
|
||||
chart:
|
||||
spec:
|
||||
chart: external-secrets
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: external-secrets
|
||||
install:
|
||||
crds: CreateReplace
|
||||
upgrade:
|
||||
crds: CreateReplace
|
||||
values:
|
||||
installCRDs: true
|
||||
metrics:
|
||||
service:
|
||||
enabled: true
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
apiVersion: external-secrets.io/v1
|
||||
kind: ClusterSecretStore
|
||||
metadata:
|
||||
name: openbao-backend
|
||||
spec:
|
||||
provider:
|
||||
vault:
|
||||
server: http://10.0.10.12:8200
|
||||
version: v2
|
||||
auth:
|
||||
tokenSecretRef:
|
||||
name: openbao-token
|
||||
key: token
|
||||
namespace: external-secrets
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: proxmox-csi-config
|
||||
namespace: kube-system
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: openbao-backend
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: proxmox-csi-config
|
||||
template:
|
||||
data:
|
||||
config.yaml: |
|
||||
clusters:
|
||||
- url: https://192.168.1.177:8006/api2/json
|
||||
insecure: true
|
||||
token_id: "{{ .token_id }}"
|
||||
token_secret: "{{ .token_secret }}"
|
||||
region: atlas
|
||||
data:
|
||||
- secretKey: token_id
|
||||
remoteRef:
|
||||
key: secret/proxmox-csi
|
||||
property: token_id
|
||||
- secretKey: token_secret
|
||||
remoteRef:
|
||||
key: secret/proxmox-csi
|
||||
property: token_secret
|
||||
11
kubernetes/infrastructure/kustomization.yaml
Normal file
11
kubernetes/infrastructure/kustomization.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- cilium/helm-release.yaml
|
||||
- cilium/l2-policy.yaml
|
||||
- proxmox-csi/helm-release.yaml
|
||||
- external-secrets/helm-release.yaml
|
||||
- external-secrets/proxmox-csi-secret.yaml
|
||||
- traefik/deployment.yaml
|
||||
- cert-manager/helm-release.yaml
|
||||
- cert-manager/cluster-issuer.yaml
|
||||
185
kubernetes/infrastructure/monitoring/logging.yaml
Normal file
185
kubernetes/infrastructure/monitoring/logging.yaml
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: loki-data-pvc
|
||||
namespace: monitoring
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 30Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: loki-config
|
||||
namespace: monitoring
|
||||
data:
|
||||
loki.yaml: |
|
||||
auth_enabled: false
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
common:
|
||||
path_prefix: /loki
|
||||
storage:
|
||||
filesystem:
|
||||
chunks_directory: /loki/chunks
|
||||
rules_directory: /loki/rules
|
||||
replication_factor: 1
|
||||
ring:
|
||||
instance_addr: 127.0.0.1
|
||||
kvstore:
|
||||
store: inmemory
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2024-01-01
|
||||
store: tsdb
|
||||
object_store: filesystem
|
||||
schema: v13
|
||||
index:
|
||||
prefix: index_
|
||||
period: 24h
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: loki
|
||||
namespace: monitoring
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: loki
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: loki
|
||||
spec:
|
||||
securityContext:
|
||||
fsGroup: 10001
|
||||
containers:
|
||||
- name: loki
|
||||
image: grafana/loki:latest
|
||||
args:
|
||||
- -config.file=/etc/loki/loki.yaml
|
||||
ports:
|
||||
- containerPort: 3100
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/loki
|
||||
- name: storage
|
||||
mountPath: /loki
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: loki-config
|
||||
- name: storage
|
||||
persistentVolumeClaim:
|
||||
claimName: loki-data-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: loki
|
||||
namespace: monitoring
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 3100
|
||||
targetPort: 3100
|
||||
selector:
|
||||
app: loki
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: vector-agent
|
||||
namespace: monitoring
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: vector-agent
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["namespaces", "nodes", "pods"]
|
||||
verbs: ["list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: vector-agent
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: vector-agent
|
||||
namespace: monitoring
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: vector-agent
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: vector-config
|
||||
namespace: monitoring
|
||||
data:
|
||||
vector.yaml: |
|
||||
data_dir: "/var/lib/vector"
|
||||
sources:
|
||||
kubernetes_logs:
|
||||
type: "kubernetes_logs"
|
||||
sinks:
|
||||
loki:
|
||||
type: "loki"
|
||||
inputs:
|
||||
- "kubernetes_logs"
|
||||
endpoint: "http://loki.monitoring.svc.cluster.local:3100"
|
||||
encoding:
|
||||
codec: "json"
|
||||
labels:
|
||||
pod_namespace: "{{ kubernetes.pod_namespace }}"
|
||||
pod_name: "{{ kubernetes.pod_name }}"
|
||||
container_name: "{{ kubernetes.container_name }}"
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: vector-agent
|
||||
namespace: monitoring
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: vector-agent
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: vector-agent
|
||||
spec:
|
||||
serviceAccountName: vector-agent
|
||||
containers:
|
||||
- name: vector
|
||||
image: timberio/vector:latest-alpine
|
||||
env:
|
||||
- name: VECTOR_CONFIG
|
||||
value: /etc/vector/vector.yaml
|
||||
volumeMounts:
|
||||
- name: vector-config
|
||||
mountPath: /etc/vector
|
||||
- name: vector-data
|
||||
mountPath: /var/lib/vector
|
||||
- name: var-log-pods
|
||||
mountPath: /var/log/pods
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: vector-config
|
||||
configMap:
|
||||
name: vector-config
|
||||
- name: vector-data
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: var-log-pods
|
||||
hostPath:
|
||||
path: /var/log/pods
|
||||
125
kubernetes/infrastructure/monitoring/telemetry.yaml
Normal file
125
kubernetes/infrastructure/monitoring/telemetry.yaml
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: monitoring
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: victoria-metrics-pvc
|
||||
namespace: monitoring
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: grafana-data-pvc
|
||||
namespace: monitoring
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: proxmox-csi-general
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: victoriametrics
|
||||
namespace: monitoring
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: victoriametrics
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: victoriametrics
|
||||
spec:
|
||||
containers:
|
||||
- name: victoriametrics
|
||||
image: victoriametrics/victoria-metrics:latest
|
||||
args:
|
||||
- -storageDataPath=/vmagent-data
|
||||
- -retentionPeriod=1y
|
||||
ports:
|
||||
- containerPort: 8428
|
||||
volumeMounts:
|
||||
- name: victoria-metrics-data
|
||||
mountPath: /vmagent-data
|
||||
volumes:
|
||||
- name: victoria-metrics-data
|
||||
persistentVolumeClaim:
|
||||
claimName: victoria-metrics-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: victoriametrics
|
||||
namespace: monitoring
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8428
|
||||
targetPort: 8428
|
||||
selector:
|
||||
app: victoriametrics
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: grafana
|
||||
namespace: monitoring
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: grafana
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: grafana
|
||||
spec:
|
||||
securityContext:
|
||||
fsGroup: 472
|
||||
containers:
|
||||
- name: grafana
|
||||
image: grafana/grafana:latest
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
env:
|
||||
- name: GF_SECURITY_ADMIN_USER
|
||||
value: "admin"
|
||||
- name: GF_SECURITY_ADMIN_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: grafana-credentials
|
||||
key: GF_SECURITY_ADMIN_PASSWORD
|
||||
volumeMounts:
|
||||
- name: grafana-data
|
||||
mountPath: /var/lib/grafana
|
||||
volumes:
|
||||
- name: grafana-data
|
||||
persistentVolumeClaim:
|
||||
claimName: grafana-data-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: grafana
|
||||
namespace: monitoring
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 3000
|
||||
targetPort: 3000
|
||||
selector:
|
||||
app: grafana
|
||||
43
kubernetes/infrastructure/proxmox-csi/helm-release.yaml
Normal file
43
kubernetes/infrastructure/proxmox-csi/helm-release.yaml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: proxmox-csi-plugin
|
||||
namespace: kube-system
|
||||
spec:
|
||||
interval: 24h
|
||||
type: oci
|
||||
url: oci://ghcr.io/sergelogvinov/charts
|
||||
---
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: proxmox-csi-plugin
|
||||
namespace: kube-system
|
||||
spec:
|
||||
interval: 1h
|
||||
chart:
|
||||
spec:
|
||||
chart: proxmox-csi-plugin
|
||||
version: "0.5.12"
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: proxmox-csi-plugin
|
||||
install:
|
||||
crds: CreateReplace
|
||||
upgrade:
|
||||
crds: CreateReplace
|
||||
values:
|
||||
existingConfigSecret: proxmox-csi-config
|
||||
storageClass:
|
||||
- name: proxmox-csi-db
|
||||
storage: astra
|
||||
cache: none
|
||||
ssd: true
|
||||
storageFormat: raw
|
||||
blockSize: "16384"
|
||||
- name: proxmox-csi-general
|
||||
storage: astra
|
||||
cache: none
|
||||
ssd: true
|
||||
storageFormat: raw
|
||||
blockSize: "65536"
|
||||
169
kubernetes/infrastructure/traefik/deployment.yaml
Normal file
169
kubernetes/infrastructure/traefik/deployment.yaml
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: traefik
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: traefik
|
||||
namespace: traefik
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: traefik-ingress-controller
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services", "endpoints", "secrets", "nodes", "configmaps"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["discovery.k8s.io"]
|
||||
resources: ["endpointslices"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["extensions", "networking.k8s.io"]
|
||||
resources: ["ingresses", "ingressclasses"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["extensions", "networking.k8s.io"]
|
||||
resources: ["ingresses/status"]
|
||||
verbs: ["update"]
|
||||
- apiGroups: ["traefik.io", "traefik.containo.us"]
|
||||
resources: ["*"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: traefik-ingress-controller
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: traefik-ingress-controller
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: traefik
|
||||
namespace: traefik
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: IngressClass
|
||||
metadata:
|
||||
name: traefik
|
||||
annotations:
|
||||
ingressclass.kubernetes.io/is-default-class: "true"
|
||||
spec:
|
||||
controller: traefik.io/ingress-controller
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: traefik
|
||||
namespace: traefik
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
externalTrafficPolicy: Local
|
||||
loadBalancerIP: 10.0.30.200
|
||||
ports:
|
||||
- name: web
|
||||
port: 80
|
||||
targetPort: 8000
|
||||
- name: websecure
|
||||
port: 443
|
||||
targetPort: 8443
|
||||
selector:
|
||||
app: traefik
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: traefik
|
||||
namespace: traefik
|
||||
spec:
|
||||
serviceName: traefik
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: traefik
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: traefik
|
||||
spec:
|
||||
serviceAccountName: traefik
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchLabels:
|
||||
app: traefik
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
containers:
|
||||
- name: traefik
|
||||
image: docker.io/traefik:v3.7.13
|
||||
args:
|
||||
- "--entryPoints.web.address=:8000/tcp"
|
||||
- "--entryPoints.web.allowACMEByPass=true"
|
||||
- "--entryPoints.websecure.address=:8443/tcp"
|
||||
- "--entryPoints.websecure.http.tls=true"
|
||||
- "--entryPoints.web.http.redirections.entryPoint.to=:443"
|
||||
- "--entryPoints.web.http.redirections.entryPoint.scheme=https"
|
||||
- "--entryPoints.web.http.redirections.entryPoint.permanent=true"
|
||||
- "--providers.kubernetesingress.allowEmptyServices=true"
|
||||
- "--providers.kubernetesingress.ingressendpoint.publishedservice=traefik/traefik"
|
||||
- "--entryPoints.websecure.transport.respondingTimeouts.readTimeout=3600s"
|
||||
- "--entryPoints.websecure.transport.respondingTimeouts.writeTimeout=3600s"
|
||||
- "--entryPoints.websecure.transport.respondingTimeouts.idleTimeout=3600s"
|
||||
- "--providers.kubernetesingress=true"
|
||||
- "--providers.kubernetesingress.ingressclass=traefik"
|
||||
- "--providers.kubernetescrd=true"
|
||||
- "--api.dashboard=true"
|
||||
- "--ping=true"
|
||||
- "--log.level=INFO"
|
||||
ports:
|
||||
- name: web
|
||||
containerPort: 8000
|
||||
- name: websecure
|
||||
containerPort: 8443
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 100Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 400Mi
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: authentik
|
||||
namespace: traefik
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: http://authentik-server.authentik.svc.cluster.local:80/outpost.goauthentik.io/auth/traefik
|
||||
trustForwardHeader: true
|
||||
authResponseHeaders:
|
||||
- X-authentik-username
|
||||
- X-authentik-groups
|
||||
- X-authentik-email
|
||||
- X-authentik-name
|
||||
- X-authentik-uid
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: local-only
|
||||
namespace: traefik
|
||||
spec:
|
||||
ipAllowList:
|
||||
sourceRange:
|
||||
- 127.0.0.1/32
|
||||
- 192.168.1.0/24
|
||||
- 10.0.10.0/24
|
||||
- 10.0.30.64/26
|
||||
- 10.0.30.128/26
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: ServersTransport
|
||||
metadata:
|
||||
name: pve-transport
|
||||
namespace: traefik
|
||||
spec:
|
||||
insecureSkipVerify: true
|
||||
31
repomix.config.json
Normal file
31
repomix.config.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"output": {
|
||||
"filePath": "repomix-output.xml",
|
||||
"style": "xml",
|
||||
"removeComments": false,
|
||||
"removeEmptyLines": true,
|
||||
"showLineNumbers": false,
|
||||
"copyToClipboard": true
|
||||
},
|
||||
"include": [
|
||||
"**/*",
|
||||
"docs/state/**"
|
||||
],
|
||||
"ignore": {
|
||||
"useGitignore": true,
|
||||
"useDefaultPatterns": true,
|
||||
"customPatterns": [
|
||||
"!docs/state/**",
|
||||
"**/.terraform/**",
|
||||
"**/.terraform.lock.hcl",
|
||||
"**/*.tfstate*",
|
||||
"**/terraform.tfvars",
|
||||
"vpn/*.priv",
|
||||
"**/*.priv",
|
||||
"**/*.key"
|
||||
]
|
||||
},
|
||||
"security": {
|
||||
"enableSecurityCheck": true
|
||||
}
|
||||
}
|
||||
89
scripts/collect_state.sh
Executable file
89
scripts/collect_state.sh
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
STATE_DIR="${REPO_ROOT}/scripts/state"
|
||||
STATE_OUT_DIR="${REPO_ROOT}/docs/state"
|
||||
TARGET="${1:-all}"
|
||||
|
||||
MODULES=(
|
||||
"00_workstation.sh"
|
||||
"01_pve.sh"
|
||||
"02_vps.sh"
|
||||
"03_vyos.sh"
|
||||
"04_tier0.sh"
|
||||
"05_k8s.sh"
|
||||
)
|
||||
|
||||
mkdir -p "${STATE_OUT_DIR}"
|
||||
|
||||
generate_header() {
|
||||
local mod_name="$1"
|
||||
local timestamp
|
||||
local branch
|
||||
local short_hash
|
||||
local commit_msg
|
||||
|
||||
timestamp=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||
branch=$(git -C "${REPO_ROOT}" branch --show-current 2>/dev/null || echo "unknown")
|
||||
short_hash=$(git -C "${REPO_ROOT}" rev-parse --short HEAD 2>/dev/null || echo "none")
|
||||
commit_msg=$(git -C "${REPO_ROOT}" log -1 --format='%s' 2>/dev/null || echo "none")
|
||||
|
||||
cat <<EOF
|
||||
# Sovereign C2 Runtime: ${mod_name}
|
||||
**Срез:** ${timestamp} | **Git:** ${branch}@${short_hash} ("${commit_msg}")
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
run_single_module() {
|
||||
local mod="$1"
|
||||
local mod_name="${mod%.sh}"
|
||||
local script="${STATE_DIR}/${mod}"
|
||||
local out_file="${STATE_OUT_DIR}/${mod_name}.md"
|
||||
local tmp_file="${out_file}.tmp"
|
||||
|
||||
echo "==> Сбор среза: ${mod_name} -> docs/state/${mod_name}.md..."
|
||||
generate_header "${mod_name}" > "${tmp_file}"
|
||||
if [[ -x "${script}" ]]; then
|
||||
"${script}" >> "${tmp_file}"
|
||||
else
|
||||
bash "${script}" >> "${tmp_file}"
|
||||
fi
|
||||
mv "${tmp_file}" "${out_file}"
|
||||
echo "✔ Срез ${mod_name} сохранен в docs/state/${mod_name}.md"
|
||||
}
|
||||
|
||||
if [[ "${TARGET}" == "all" ]]; then
|
||||
echo "==> Сбор полного снимка Sovereign C2 (все модули)..."
|
||||
for mod in "${MODULES[@]}"; do
|
||||
run_single_module "${mod}"
|
||||
done
|
||||
echo "✔ Все модули среза успешно обновлены в docs/state/"
|
||||
else
|
||||
case "${TARGET}" in
|
||||
00_workstation|00_workstation.sh|workstation|host)
|
||||
run_single_module "00_workstation.sh"
|
||||
;;
|
||||
01_pve|01_pve.sh|pve)
|
||||
run_single_module "01_pve.sh"
|
||||
;;
|
||||
02_vps|02_vps.sh|vps)
|
||||
run_single_module "02_vps.sh"
|
||||
;;
|
||||
03_vyos|03_vyos.sh|vyos|net)
|
||||
run_single_module "03_vyos.sh"
|
||||
;;
|
||||
04_tier0|04_tier0.sh|tier0)
|
||||
run_single_module "04_tier0.sh"
|
||||
;;
|
||||
05_k8s|05_k8s.sh|k8s|talos)
|
||||
run_single_module "05_k8s.sh"
|
||||
;;
|
||||
*)
|
||||
echo "Неизвестный модуль: ${TARGET}"
|
||||
echo "Доступны: all, workstation (host), pve, vps, vyos (net), tier0, k8s (talos)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
9
scripts/layers/00_host.sh
Executable file
9
scripts/layers/00_host.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
||||
ensure_prerequisites
|
||||
load_secrets_to_ram
|
||||
|
||||
log_info "[Layer 0: PVE Host] Накатка директорий и прав ZFS..."
|
||||
ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${REPO_ROOT}/ansible/playbooks/01_pve_host_day0.yml"
|
||||
log_ok "Layer 0 готов."
|
||||
9
scripts/layers/01_net.sh
Executable file
9
scripts/layers/01_net.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
||||
ensure_prerequisites
|
||||
load_secrets_to_ram
|
||||
|
||||
log_info "[Layer 1: VyOS & Perimeter] Накатка конфигурации сети..."
|
||||
ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${REPO_ROOT}/ansible/playbooks/02_vyos_network_day0.yml"
|
||||
log_ok "Layer 1 готов."
|
||||
26
scripts/layers/02_tier0.sh
Executable file
26
scripts/layers/02_tier0.sh
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
||||
ensure_prerequisites
|
||||
load_secrets_to_ram
|
||||
|
||||
log_info "[Layer 2: Tier-0 Air-Gap] Подъем базовых контейнеров через Tofu..."
|
||||
cd "${REPO_ROOT}/tofu" && tofu apply -target=proxmox_virtual_environment_container.dns0 \
|
||||
-target=proxmox_virtual_environment_container.vault0 \
|
||||
-target=proxmox_virtual_environment_container.git0 \
|
||||
-target=proxmox_virtual_environment_container.storage0 \
|
||||
-target=proxmox_virtual_environment_container.registry0 -auto-approve
|
||||
|
||||
log_info "[Layer 2: Tier-0 Air-Gap] Применение ZFS-маунтов и прав на хосте Proxmox..."
|
||||
ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${REPO_ROOT}/ansible/playbooks/01_pve_host_day0.yml"
|
||||
|
||||
log_info "[Layer 2: Tier-0 Air-Gap] Конфигурация базовых сервисов..."
|
||||
for pb in 03_zot_registry.yml 04_technitium_dns.yml 05_openbao_vault.yml 06_forgejo_git.yml 07_nas_storage.yml; do
|
||||
ansible-playbook -i "${REPO_ROOT}/ansible/inventory.yml" "${REPO_ROOT}/ansible/playbooks/${pb}"
|
||||
done
|
||||
|
||||
unseal_vault
|
||||
|
||||
log_info "[Layer 2: Tier-0 Air-Gap] Доведение полного стейта Tofu..."
|
||||
cd "${REPO_ROOT}/tofu" && tofu apply -auto-approve
|
||||
log_ok "Layer 2 готов."
|
||||
17
scripts/layers/03_talos.sh
Executable file
17
scripts/layers/03_talos.sh
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
||||
ensure_prerequisites
|
||||
load_secrets_to_ram
|
||||
unseal_vault
|
||||
|
||||
log_info "[Layer 3: Talos & Kubernetes] Проверка конфигураций машинных манифестов..."
|
||||
if [[ ! -f "${REPO_ROOT}/talos/clusterconfig/controlplane.yaml" ]]; then
|
||||
log_info "Генерация машинных конфигураций Talos..."
|
||||
cd "${REPO_ROOT}" && talos/generate_config.sh
|
||||
fi
|
||||
|
||||
log_info "[Layer 3: Talos & Kubernetes] Бутстрап кластера..."
|
||||
cd "${REPO_ROOT}/talos" && ./bootstrap.sh
|
||||
sync_k8s_vault_token
|
||||
log_ok "Layer 3 готов."
|
||||
8
scripts/layers/04_apps.sh
Executable file
8
scripts/layers/04_apps.sh
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
||||
ensure_prerequisites
|
||||
|
||||
log_info "[Layer 4: Apps] Применение манифестов FluxCD..."
|
||||
kubectl apply -f "${REPO_ROOT}/kubernetes/bootstrap/sync.yaml"
|
||||
log_ok "Layer 4 готов."
|
||||
37
scripts/layers/gc.sh
Executable file
37
scripts/layers/gc.sh
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
||||
ensure_prerequisites
|
||||
|
||||
log_info "🧹 Запуск генеральной очистки кластера (dep gc)..."
|
||||
|
||||
# 1. Удаление зомби-нод в статусе NotReady
|
||||
NOT_READY_NODES=$(kubectl get nodes --no-headers 2>/dev/null | grep 'NotReady' | awk '{print $1}' || true)
|
||||
if [[ -n "${NOT_READY_NODES}" ]]; then
|
||||
for node in ${NOT_READY_NODES}; do
|
||||
log_warn "Удаляем мертвую ноду: ${node}"
|
||||
kubectl delete node "${node}" --timeout=5s 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
|
||||
# 2. Мгновенная зачистка зависших в Terminating
|
||||
kubectl get pods -A --no-headers 2>/dev/null | awk '/Terminating/ {print $1, $2}' | while read -r ns pod; do
|
||||
log_warn "Принудительно удаляем: ${ns}/${pod}"
|
||||
kubectl -n "${ns}" delete pod "${pod}" --force --grace-period=0 2>/dev/null || true
|
||||
done
|
||||
|
||||
# 3. Сброс бэкоффа для упавших подов (CrashLoopBackOff, Error, OOMKilled, CreateContainerConfigError)
|
||||
kubectl get pods -A --no-headers 2>/dev/null | grep -E 'CrashLoopBackOff|Error|OOMKilled|CreateContainerConfigError|ImagePullBackOff' | awk '{print $1, $2}' | while read -r ns pod; do
|
||||
log_info "Сбрасываем упавший под: ${ns}/${pod}"
|
||||
kubectl -n "${ns}" delete pod "${pod}" --force --grace-period=0 2>/dev/null || true
|
||||
done
|
||||
|
||||
# 4. Очистка завершенных одноразовых Job
|
||||
COMPLETED_JOBS=$(kubectl get jobs -A --field-selector status.successful=1 --no-headers 2>/dev/null | awk '{print $1, $2}' || true)
|
||||
if [[ -n "${COMPLETED_JOBS}" ]]; then
|
||||
echo "${COMPLETED_JOBS}" | while read -r ns job; do
|
||||
kubectl -n "${ns}" delete job "${job}" >/dev/null 2>&1 || true
|
||||
done
|
||||
fi
|
||||
|
||||
log_ok "Кластер очищен. Все сервисы пересоздаются против живых БД и NFS."
|
||||
27
scripts/layers/reset.sh
Executable file
27
scripts/layers/reset.sh
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
||||
|
||||
log_warn "ВНИМАНИЕ! Полная зачистка всех ВМ и LXC на Proxmox VE (host: proxmox)."
|
||||
read -r -p "Введите 'NUKE' для уничтожения: " confirm
|
||||
if [[ "${confirm}" != "NUKE" ]]; then
|
||||
echo "Отмена операции."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log_info "Уничтожение виртуальных машин и контейнеров..."
|
||||
ssh proxmox bash << 'SSHEOF'
|
||||
for id in 100 201 202 203; do
|
||||
qm stop $id --skiplock 1 2>/dev/null || true
|
||||
qm destroy $id --purge 1 --destroy-unreferenced-disks 1 2>/dev/null || true
|
||||
done
|
||||
for id in 101 102 103 104 105; do
|
||||
pct stop $id --skiplock 1 2>/dev/null || true
|
||||
pct destroy $id --purge 1 --force 1 2>/dev/null || true
|
||||
done
|
||||
SSHEOF
|
||||
|
||||
log_info "Очистка локального стейта OpenTofu..."
|
||||
rm -f "${REPO_ROOT}/tofu/terraform.tfstate"* "${REPO_ROOT}/tofu/.terraform.tfstate.lock.info"
|
||||
rm -f "${RAM_CACHE}"
|
||||
log_ok "Сервер зачищен до голого железа."
|
||||
96
scripts/lib/common.sh
Executable file
96
scripts/lib/common.sh
Executable file
|
|
@ -0,0 +1,96 @@
|
|||
# scripts/lib/common.sh
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
KDBX_PATH="${HOME}/Projects/atlas-secrets.kdbx"
|
||||
RAM_CACHE="/dev/shm/.atlas_secrets_cache"
|
||||
# Цвета вывода
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
log_info() { echo -e "${BLUE}==>${NC} $*"; }
|
||||
log_ok() { echo -e "${GREEN}✔${NC} $*"; }
|
||||
log_warn() { echo -e "${YELLOW}⚠${NC} $*"; }
|
||||
log_err() { echo -e "${RED}✖${NC} $*"; }
|
||||
ensure_prerequisites() {
|
||||
if ! ssh-add -l >/dev/null 2>&1; then
|
||||
ssh-add ~/.ssh/id_ed25519 2>/dev/null || true
|
||||
fi
|
||||
if ! ip route get 10.0.10.12 2>/dev/null | grep -q "192.168.1.2"; then
|
||||
log_info "Восстанавливаем маршрут к 10.0.0.0/16 через VyOS (192.168.1.2)..."
|
||||
sudo ip route replace 10.0.0.0/16 via 192.168.1.2 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
load_secrets_to_ram() {
|
||||
if [[ -f "${RAM_CACHE}" ]]; then
|
||||
source "${RAM_CACHE}"
|
||||
return 0
|
||||
fi
|
||||
log_info "🔐 Вход в защищенный контур (KeePassXC)..."
|
||||
read -s -p "Master Password: " KP_PASS
|
||||
echo ""
|
||||
log_info "Загрузка секретов в оперативную память (/dev/shm)..."
|
||||
PVE_TOKEN=$(echo "${KP_PASS}" | keepassxc-cli show -q -a Password "${KDBX_PATH}" "ProxmoxAPI" | tr -d '\r\n ')
|
||||
TF_PASS=$(echo "${KP_PASS}" | keepassxc-cli show -q -a Password "${KDBX_PATH}" "TofuState" | tr -d '\r\n ')
|
||||
BAO_TOKEN=$(echo "${KP_PASS}" | keepassxc-cli show -q -a Password "${KDBX_PATH}" "OpenBaoToken" | tr -d '\r\n ')
|
||||
BAO_UNSEAL=$(echo "${KP_PASS}" | keepassxc-cli show -q -a Password "${KDBX_PATH}" "OpenBaoUnseal" | tr -d '\r\n ')
|
||||
TECH_PASS=$(echo "${KP_PASS}" | keepassxc-cli show -q -a Password "${KDBX_PATH}" "Technitium" 2>/dev/null | tr -d '\r\n ' || echo "admin")
|
||||
VW_ADMIN=$(echo "${KP_PASS}" | keepassxc-cli show -q -a Password "${KDBX_PATH}" "VaultwardenAdmin" | tr -d '\r\n ')
|
||||
unset KP_PASS
|
||||
touch "${RAM_CACHE}"
|
||||
chmod 600 "${RAM_CACHE}"
|
||||
{
|
||||
printf 'export %s=%q\n' "PROXMOX_VE_API_TOKEN" "${PVE_TOKEN}"
|
||||
printf 'export %s=%q\n' "TF_VAR_proxmox_api_token" "${PVE_TOKEN}"
|
||||
printf 'export %s=%q\n' "TF_VAR_state_passphrase" "${TF_PASS}"
|
||||
printf 'export %s=%q\n' "PROXMOX_VE_ENDPOINT" "https://192.168.1.177:8006/"
|
||||
printf 'export %s=%q\n' "TF_VAR_ssh_public_key" "$(cat ~/.ssh/id_ed25519.pub)"
|
||||
printf 'export %s=%q\n' "VAULT_ADDR" "http://10.0.10.12:8200"
|
||||
printf 'export %s=%q\n' "VAULT_TOKEN" "${BAO_TOKEN}"
|
||||
printf 'export %s=%q\n' "VAULT_UNSEAL_KEY" "${BAO_UNSEAL}"
|
||||
printf 'export %s=%q\n' "TECHNITIUM_PASSWORD" "${TECH_PASS}"
|
||||
printf 'export %s=%q\n' "TF_VAR_vaultwarden_admin_token" "${VW_ADMIN}"
|
||||
} > "${RAM_CACHE}"
|
||||
source "${RAM_CACHE}"
|
||||
unset PVE_TOKEN TF_PASS BAO_TOKEN BAO_UNSEAL TECH_PASS VW_ADMIN
|
||||
log_ok "Секреты безопасно загружены в RAM"
|
||||
}
|
||||
# АВТО-СИНХРОНИЗАЦИЯ: передает токен в K8s без ручных команд
|
||||
sync_k8s_vault_token() {
|
||||
if kubectl --request-timeout=2s cluster-info >/dev/null 2>&1; then
|
||||
log_info "Синхронизация токена OpenBao в Kubernetes (namespace: external-secrets)..."
|
||||
kubectl create namespace external-secrets --dry-run=client -o yaml | kubectl apply -f - >/dev/null 2>&1 || true
|
||||
kubectl -n external-secrets create secret generic openbao-token \
|
||||
--from-literal=token="${VAULT_TOKEN}" \
|
||||
--dry-run=client -o yaml | kubectl apply -f - >/dev/null 2>&1
|
||||
# Сбрасываем кэш сессий в контроллере ExternalSecrets
|
||||
kubectl -n external-secrets rollout restart deployment external-secrets >/dev/null 2>&1 || true
|
||||
log_ok "Токен OpenBao в Kubernetes актуализирован, контроллер перезапущен."
|
||||
fi
|
||||
}
|
||||
unseal_vault() {
|
||||
load_secrets_to_ram
|
||||
local seal_status
|
||||
seal_status=$(curl -s --connect-timeout 2 "${VAULT_ADDR}/v1/sys/seal-status" 2>/dev/null || echo "")
|
||||
if [[ -z "${seal_status}" ]]; then
|
||||
log_warn "OpenBao (${VAULT_ADDR}) недоступен по сети. Пропуск ансила."
|
||||
return 0
|
||||
fi
|
||||
if echo "${seal_status}" | grep -q '"sealed":true'; then
|
||||
log_info "OpenBao запечатан! Выполняем ансил из памяти..."
|
||||
local resp
|
||||
resp=$(printf '{"key":"%s"}' "${VAULT_UNSEAL_KEY}" | curl -s -X POST -H "Content-Type: application/json" --data-binary @- "${VAULT_ADDR}/v1/sys/unseal")
|
||||
if echo "${resp}" | grep -q '"sealed":false'; then
|
||||
log_ok "OpenBao успешно распечатан."
|
||||
sync_k8s_vault_token
|
||||
else
|
||||
log_err "Ошибка ансила OpenBao: ${resp}"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_ok "OpenBao распечатан."
|
||||
sync_k8s_vault_token
|
||||
fi
|
||||
}
|
||||
43
scripts/state/00_workstation.sh
Executable file
43
scripts/state/00_workstation.sh
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
|
||||
echo "## 0. Рабочая станция администратора (Operator Environment)"
|
||||
echo "### Инфраструктурные SSH-хосты (~/.ssh/config):"
|
||||
echo '```text'
|
||||
if [[ -f ~/.ssh/config ]]; then
|
||||
awk '/^Host (router|proxmox|vyos|10\.|fin21|ded|incserv)/, /^$/' ~/.ssh/config
|
||||
else
|
||||
echo "Файл ~/.ssh/config не найден"
|
||||
fi
|
||||
echo '```'
|
||||
|
||||
echo "### Рабочие алиасы и функции оператора (Active Workflow Aliases):"
|
||||
echo '```bash'
|
||||
if [[ -f ~/.bashrc ]] && grep -q '# >>> ATLAS C2 WORKFLOW >>>' ~/.bashrc; then
|
||||
sed -n '/# >>> ATLAS C2 WORKFLOW >>>/,/# <<< ATLAS C2 WORKFLOW <<</p' ~/.bashrc | grep -v '>>>'
|
||||
else
|
||||
echo "# Маркер # >>> ATLAS C2 WORKFLOW >>> не найден в ~/.bashrc"
|
||||
fi
|
||||
echo '```'
|
||||
|
||||
echo "### Маршрутизация на хосте (Routing to C2):"
|
||||
echo '```text'
|
||||
ip route show | grep -E "10.0.|192.168." || echo "Маршруты к ЦОД не обнаружены"
|
||||
echo '```'
|
||||
|
||||
echo "### Версии локальных инструментов:"
|
||||
echo '```text'
|
||||
echo -n "OpenTofu: "; tofu version 2>/dev/null | head -n1 || echo "not installed"
|
||||
echo -n "Kubectl: "; kubectl version --client -o yaml 2>/dev/null | grep gitVersion | head -n1 || echo "not installed"
|
||||
echo -n "Talosctl: "; talosctl version --client --short 2>/dev/null || echo "not installed"
|
||||
echo '```'
|
||||
|
||||
echo "### Состояние локального Git-репозитория (SSOT Source):"
|
||||
echo '```text'
|
||||
git -C "${REPO_ROOT}" status -sb
|
||||
echo "Последний коммит: $(git -C "${REPO_ROOT}" log -1 --format='%h - %s (%cr)')"
|
||||
echo "Remote URL: $(git -C "${REPO_ROOT}" remote -v 2>/dev/null | head -n1 | awk '{print $1, $2}' || echo 'no remote')"
|
||||
echo '```'
|
||||
echo "---"
|
||||
19
scripts/state/01_pve.sh
Executable file
19
scripts/state/01_pve.sh
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
|
||||
SSH_CMD="ssh -n -o BatchMode=yes -o ConnectTimeout=3 proxmox"
|
||||
|
||||
echo "## 1. Гипервизор Proxmox VE (192.168.1.177)"
|
||||
echo "### Память хоста и Uptime:"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_CMD} "uptime; echo ''; free -h" 2>&1 || echo "PVE недоступен"
|
||||
echo '```'
|
||||
echo "### Здоровье и емкость ZFS-пулов:"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_CMD} "zpool list -o name,size,alloc,free,frag,cap,health; echo ''; zfs list -o name,used,avail,refer,mountpoint -r astra terra" 2>&1 || echo "Ошибка сбора ZFS"
|
||||
echo '```'
|
||||
echo "### Виртуальные машины (QEMU) и Контейнеры (LXC):"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_CMD} "qm list; echo ''; pct list" 2>&1 || echo "Ошибка получения списка ВМ/LXC"
|
||||
echo '```'
|
||||
echo "---"
|
||||
27
scripts/state/02_vps.sh
Executable file
27
scripts/state/02_vps.sh
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
|
||||
SSH_CMD="ssh -n -o BatchMode=yes -o ConnectTimeout=4 fin21"
|
||||
|
||||
echo "## 2. Периметр: Белый VPS (Host: fin21, IP: 153.76.194.24)"
|
||||
echo "### WireGuard wg0 на VPS:"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_CMD} "sudo wg show wg0" 2>&1 || echo "VPS или WireGuard недоступен"
|
||||
echo '```'
|
||||
echo "### Статус системных сервисов (Edge Stack):"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_CMD} "sudo systemctl is-active wg-quick@wg0 haproxy xray nginx | paste -d' ' -s - | awk '{print \"WireGuard:\", \$1, \"| HAProxy:\", \$2, \"| Xray:\", \$3, \"| Nginx:\", \$4}'" 2>&1 || echo "Ошибка проверки systemd"
|
||||
echo '```'
|
||||
echo "### Прослушиваемые сокеты (Ports 80, 443, 4443, 8443, 51820):"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_CMD} "sudo ss -tulpn | grep -E '80|443|4443|8443|51820'" 2>&1 || echo "Ошибка ss"
|
||||
echo '```'
|
||||
echo "### Тест аварийной заглушки Nginx (127.0.0.1:8443):"
|
||||
echo '```text'
|
||||
timeout 3s ${SSH_CMD} "curl -k -s https://127.0.0.1:8443" 2>&1 || echo "Nginx fallback не отвечает"
|
||||
echo '```'
|
||||
echo "### Конфигурация SSH-демона (sshd runtime):"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_CMD} "sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin'" 2>&1 || echo "Ошибка проверки sshd"
|
||||
echo '```'
|
||||
echo "---"
|
||||
15
scripts/state/03_vyos.sh
Executable file
15
scripts/state/03_vyos.sh
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
SSH_CMD="ssh -n -o BatchMode=yes -o ConnectTimeout=3 vyos"
|
||||
|
||||
echo "## 3. Маршрутизатор VyOS (192.168.1.2)"
|
||||
echo "### Статус WireGuard туннеля и пинг до VPS:"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_CMD} "sudo wg show wg0; echo ''; /opt/vyatta/bin/vyatta-op-cmd-wrapper ping 10.8.0.1 count 2" 2>&1 || echo "VyOS или туннель недоступен"
|
||||
echo '```'
|
||||
|
||||
echo "### Таблица маршрутизации (show ip route):"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_CMD} "/opt/vyatta/bin/vyatta-op-cmd-wrapper show ip route" 2>&1 || echo "Ошибка получения маршрутов"
|
||||
echo '```'
|
||||
echo "---"
|
||||
25
scripts/state/04_tier0.sh
Executable file
25
scripts/state/04_tier0.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
|
||||
SSH_VYOS="ssh -n -o BatchMode=yes -o ConnectTimeout=3 vyos"
|
||||
SSH_STORAGE="ssh -n -o BatchMode=yes -o ConnectTimeout=3 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -J vyos root@10.0.10.14"
|
||||
|
||||
echo "## 4. Сервисы Tier-0 (Air-Gap фундамент)"
|
||||
echo "### Technitium DNS (10.0.10.11:53):"
|
||||
echo "* **Внутренний домен (*.svo88.space -> 10.0.30.200):** $(timeout 3s ${SSH_VYOS} "dig @10.0.10.11 vw.svo88.space +short" 2>&1 | tr '\n' ' ')"
|
||||
echo "* **Внешний резолв (google.com):** $(timeout 3s ${SSH_VYOS} "dig @10.0.10.11 google.com +short" 2>&1 | head -n1)"
|
||||
echo "### OpenBao Vault (10.0.10.12:8200):"
|
||||
echo '```json'
|
||||
timeout 3s ${SSH_VYOS} "curl -s http://10.0.10.12:8200/v1/sys/seal-status" 2>&1 || echo '{"error": "Vault недоступен"}'
|
||||
echo '```'
|
||||
echo "### Zot OCI Registry (10.0.10.15:5000):"
|
||||
echo '```json'
|
||||
timeout 3s ${SSH_VYOS} "curl -s http://10.0.10.15:5000/v2/_catalog" 2>&1 || echo '{"error": "Zot недоступен"}'
|
||||
echo '```'
|
||||
echo "### Ядерный NFS nfsd (storage0 - 10.0.10.14):"
|
||||
echo '```text'
|
||||
timeout 4s ${SSH_STORAGE} "echo '== Активные экспорты ядра (exportfs):'; exportfs -v; echo ''; echo '== Емкость смонтированных ZFS-датасетов:'; df -h /media /torrents /backups" 2>/dev/null || \
|
||||
timeout 4s ssh -n -o BatchMode=yes -o ConnectTimeout=3 root@10.0.10.14 "echo '== Активные экспорты ядра (exportfs):'; exportfs -v; echo ''; echo '== Емкость смонтированных ZFS-датасетов:'; df -h /media /torrents /backups" 2>&1 || \
|
||||
echo "NFS (storage0) недоступен"
|
||||
echo '```'
|
||||
echo "---"
|
||||
42
scripts/state/05_k8s.sh
Executable file
42
scripts/state/05_k8s.sh
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
TALOSCONFIG="${REPO_ROOT}/talos/clusterconfig/talosconfig"
|
||||
KUBECONFIG_PATH="${HOME}/.kube/config"
|
||||
|
||||
echo "## 5. Kubernetes Платформа & Нагрузки"
|
||||
echo "### Участники кластера Talos (OS-level):"
|
||||
echo '```text'
|
||||
timeout 5s talosctl --talosconfig="${TALOSCONFIG}" -n 10.0.20.10 -e 10.0.20.10 get members 2>&1 || echo "Talos API недоступен"
|
||||
echo '```'
|
||||
echo "### Ноды кластера K8s:"
|
||||
echo '```text'
|
||||
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get nodes -o wide 2>&1 || echo "K8s API недоступен"
|
||||
echo '```'
|
||||
echo "### Статус ExternalSecrets (Синхронизация из Vault):"
|
||||
echo '```text'
|
||||
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get clustersecretstores,externalsecrets -A 2>&1 || echo "Не удалось получить ExternalSecrets"
|
||||
echo '```'
|
||||
echo "### Диски и тома (PVC / PV):"
|
||||
echo '```text'
|
||||
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get pvc,pv -A 2>&1 || echo "Не удалось получить PVC"
|
||||
echo '```'
|
||||
echo "### Логи ошибок Proxmox CSI Plugin (последние строки):"
|
||||
echo '```text'
|
||||
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" -n kube-system logs -l app=proxmox-csi-plugin --tail=15 --prefix=true 2>&1 || echo "Нет логов CSI"
|
||||
echo '```'
|
||||
echo "### Синхронизация GitOps (FluxCD):"
|
||||
echo '```text'
|
||||
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get gitrepositories,kustomizations,helmreleases -A 2>&1 || echo "Flux не установлен или недоступен"
|
||||
echo '```'
|
||||
echo "### Проблемные поды (Non-Running):"
|
||||
echo '```text'
|
||||
timeout 5s kubectl --kubeconfig="${KUBECONFIG_PATH}" get pods -A --field-selector=status.phase!=Running 2>&1 || echo "Все поды в статусе Running"
|
||||
echo '```'
|
||||
echo "### Реальный объем данных OpenCloud (/var/lib/opencloud/data):"
|
||||
echo '```text'
|
||||
timeout 10s kubectl --kubeconfig="${KUBECONFIG_PATH}" -n storage exec deploy/opencloud -- du -h -d 1 /var/lib/opencloud/data 2>/dev/null || \
|
||||
timeout 10s kubectl --kubeconfig="${KUBECONFIG_PATH}" -n storage exec statefulset/opencloud -- du -h -d 1 /var/lib/opencloud/data 2>&1 || \
|
||||
echo "Не удалось получить размер данных OpenCloud"
|
||||
echo '```'
|
||||
76
talos/bootstrap.sh
Executable file
76
talos/bootstrap.sh
Executable file
|
|
@ -0,0 +1,76 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
export TALOSCONFIG="${SCRIPT_DIR}/clusterconfig/talosconfig"
|
||||
KUBECONFIG_PATH="${HOME}/.kube/config"
|
||||
|
||||
NODES=("10.0.20.10" "10.0.20.11" "10.0.20.12")
|
||||
CONFIGS=(
|
||||
"${SCRIPT_DIR}/clusterconfig/controlplane.yaml"
|
||||
"${SCRIPT_DIR}/clusterconfig/worker.yaml"
|
||||
"${SCRIPT_DIR}/clusterconfig/worker.yaml"
|
||||
)
|
||||
|
||||
# 1. Ждем доступности порта API (50000)
|
||||
echo "==> [1/6] Checking Talos nodes reachability..."
|
||||
for node in "${NODES[@]}"; do
|
||||
echo -n "Checking ${node}:50000 "
|
||||
while ! nc -z -w 2 "${node}" 50000 2>/dev/null; do
|
||||
sleep 2
|
||||
echo -n "."
|
||||
done
|
||||
echo " UP!"
|
||||
done
|
||||
|
||||
# 2. Применение конфигураций нод
|
||||
echo "==> [2/6] Applying machine configurations..."
|
||||
for i in "${!NODES[@]}"; do
|
||||
node="${NODES[$i]}"
|
||||
cfg="${CONFIGS[$i]}"
|
||||
if ! talosctl apply-config --insecure --nodes "${node}" --file "${cfg}" 2>/dev/null; then
|
||||
talosctl apply-config --nodes "${node}" --endpoints "${node}" --file "${cfg}" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# 3. Бутстрап кластера etcd (проверяем, не поднят ли уже Kubernetes API)
|
||||
echo "==> [3/6] Checking control plane bootstrap..."
|
||||
if nc -z -w 2 10.0.20.10 6443 2>/dev/null; then
|
||||
echo "==> Kubernetes API (port 6443) is ALREADY active and healthy! Skipping bootstrap."
|
||||
else
|
||||
echo "==> Initiating etcd bootstrap on 10.0.20.10..."
|
||||
talosctl bootstrap --nodes 10.0.20.10 --endpoints 10.0.20.10 2>/dev/null || true
|
||||
sleep 5
|
||||
fi
|
||||
|
||||
# 4. Выкачивание kubeconfig в системный путь
|
||||
echo "==> [4/6] Fetching kubeconfig..."
|
||||
mkdir -p "${HOME}/.kube"
|
||||
until talosctl kubeconfig "${KUBECONFIG_PATH}" --nodes 10.0.20.10 --endpoints 10.0.20.10 --force 2>/dev/null; do
|
||||
sleep 2
|
||||
echo -n "."
|
||||
done
|
||||
cp -f "${KUBECONFIG_PATH}" "${SCRIPT_DIR}/kubeconfig"
|
||||
echo " OK!"
|
||||
|
||||
# 5. Установка Cilium CNI через Helm
|
||||
echo "==> [5/6] Deploying Cilium CNI (Day-0 eBPF Network)..."
|
||||
helm repo add cilium https://helm.cilium.io/ --force-update >/dev/null 2>&1 || true
|
||||
helm upgrade --install cilium cilium/cilium \
|
||||
--version 1.15.5 \
|
||||
--namespace kube-system \
|
||||
--kubeconfig "${KUBECONFIG_PATH}" \
|
||||
-f "${REPO_ROOT}/kubernetes/infrastructure/network/cilium/values.yaml"
|
||||
|
||||
echo "==> Applying L2 Announcement Policy..."
|
||||
kubectl --kubeconfig "${KUBECONFIG_PATH}" apply -f "${REPO_ROOT}/kubernetes/infrastructure/network/cilium/l2-policy.yaml"
|
||||
|
||||
# 6. Ожидание перехода всех нод в статус Ready
|
||||
echo "==> [6/6] Waiting for all nodes to become Ready..."
|
||||
kubectl --kubeconfig "${KUBECONFIG_PATH}" wait --for=condition=Ready nodes --all --timeout=180s
|
||||
|
||||
echo ""
|
||||
echo "🎉 Cluster is FULLY READY and OPERATIONAL!"
|
||||
kubectl --kubeconfig "${KUBECONFIG_PATH}" get nodes -o wide
|
||||
21
talos/generate_config.sh
Executable file
21
talos/generate_config.sh
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
mkdir -p talos/clusterconfig
|
||||
|
||||
if [ ! -f "talos/secrets.yaml" ]; then
|
||||
talosctl gen secrets -o talos/secrets.yaml
|
||||
fi
|
||||
chmod 0600 talos/secrets.yaml
|
||||
|
||||
talosctl gen config atlas https://10.0.20.10:6443 \
|
||||
--with-secrets talos/secrets.yaml \
|
||||
--config-patch @talos/patches/common.yaml \
|
||||
--config-patch-worker @talos/patches/worker.yaml \
|
||||
--install-disk /dev/vda \
|
||||
--output-dir talos/clusterconfig \
|
||||
--with-docs=false \
|
||||
--with-examples=false \
|
||||
--force
|
||||
|
||||
chmod 0600 talos/clusterconfig/*
|
||||
29
talos/patches/common.yaml
Normal file
29
talos/patches/common.yaml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
machine:
|
||||
registries:
|
||||
mirrors:
|
||||
docker.io:
|
||||
overridePath: true
|
||||
endpoints:
|
||||
- http://10.0.10.15:5000/v2/docker.io
|
||||
ghcr.io:
|
||||
overridePath: true
|
||||
endpoints:
|
||||
- http://10.0.10.15:5000/v2/ghcr.io
|
||||
registry.k8s.io:
|
||||
overridePath: true
|
||||
endpoints:
|
||||
- http://10.0.10.15:5000/v2/k8s.io
|
||||
quay.io:
|
||||
overridePath: true
|
||||
endpoints:
|
||||
- http://10.0.10.15:5000/v2/quay.io
|
||||
---
|
||||
apiVersion: v1alpha1
|
||||
kind: ResolverConfig
|
||||
nameservers:
|
||||
- address: 10.0.10.11
|
||||
- address: 10.0.20.1
|
||||
---
|
||||
apiVersion: v1alpha1
|
||||
kind: KubeFlannelCNIConfig
|
||||
$patch: delete
|
||||
12
talos/patches/worker.yaml
Normal file
12
talos/patches/worker.yaml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
machine:
|
||||
nodeLabels:
|
||||
topology.kubernetes.io/region: atlas
|
||||
topology.kubernetes.io/zone: pve0
|
||||
network:
|
||||
interfaces:
|
||||
- interface: ens18
|
||||
dhcp: true
|
||||
- interface: ens19
|
||||
dhcp: true
|
||||
---
|
||||
453
tofu/compute.tf
Normal file
453
tofu/compute.tf
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
variable "talos_iso_file_id" {
|
||||
type = string
|
||||
description = "Proxmox file ID for the Talos Linux ISO"
|
||||
default = "local:iso/talos-amd64.iso"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# ROUTING & EDGE (VyOS)
|
||||
# ==============================================================================
|
||||
|
||||
resource "proxmox_virtual_environment_vm" "vyos_router" {
|
||||
vm_id = 100
|
||||
name = "vyos-router"
|
||||
node_name = "pve0"
|
||||
started = true
|
||||
|
||||
cpu {
|
||||
cores = 2
|
||||
type = "host"
|
||||
}
|
||||
|
||||
memory {
|
||||
dedicated = 2048
|
||||
}
|
||||
|
||||
disk {
|
||||
datastore_id = "astra"
|
||||
file_id = "local:iso/vyos-1.5-cloudinit.img"
|
||||
interface = "virtio0"
|
||||
size = 10
|
||||
}
|
||||
|
||||
boot_order = ["virtio0"]
|
||||
|
||||
# VLAN 99: WAN_TRUNK
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
model = "virtio"
|
||||
}
|
||||
|
||||
# VLAN 10: TIER0 (MGMT)
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 10
|
||||
model = "virtio"
|
||||
}
|
||||
|
||||
# VLAN 20: K8S
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 20
|
||||
model = "virtio"
|
||||
}
|
||||
|
||||
# VLAN 30: LAN_CLIENTS
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 30
|
||||
model = "virtio"
|
||||
}
|
||||
|
||||
operating_system {
|
||||
type = "l26"
|
||||
}
|
||||
initialization {
|
||||
datastore_id = "astra"
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = "192.168.1.2/24"
|
||||
gateway = "192.168.1.1"
|
||||
}
|
||||
}
|
||||
user_account {
|
||||
username = "vyos"
|
||||
keys = [var.ssh_public_key]
|
||||
}
|
||||
}
|
||||
|
||||
agent {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# TIER-0 LXC CONTAINERS (AIR-GAP FOUNDATION)
|
||||
# ==============================================================================
|
||||
|
||||
resource "proxmox_virtual_environment_container" "dns0" {
|
||||
vm_id = 101
|
||||
node_name = "pve0"
|
||||
unprivileged = true
|
||||
started = true
|
||||
|
||||
cpu { cores = 1 }
|
||||
memory { dedicated = 512 }
|
||||
|
||||
disk {
|
||||
datastore_id = "local"
|
||||
size = 2
|
||||
}
|
||||
|
||||
network_interface {
|
||||
name = "eth0"
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 10
|
||||
}
|
||||
|
||||
initialization {
|
||||
hostname = "dns0"
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = "10.0.10.11/24"
|
||||
gateway = "10.0.10.1"
|
||||
}
|
||||
}
|
||||
user_account { keys = [var.ssh_public_key] }
|
||||
}
|
||||
|
||||
operating_system {
|
||||
template_file_id = "local:vztmpl/debian-12-standard_amd64.tar.zst"
|
||||
type = "debian"
|
||||
}
|
||||
|
||||
features {
|
||||
nesting = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_container" "vault0" {
|
||||
vm_id = 102
|
||||
node_name = "pve0"
|
||||
unprivileged = true
|
||||
started = true
|
||||
|
||||
cpu { cores = 1 }
|
||||
memory { dedicated = 512 }
|
||||
|
||||
disk {
|
||||
datastore_id = "local"
|
||||
size = 4
|
||||
}
|
||||
|
||||
network_interface {
|
||||
name = "eth0"
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 10
|
||||
}
|
||||
|
||||
initialization {
|
||||
hostname = "vault0"
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = "10.0.10.12/24"
|
||||
gateway = "10.0.10.1"
|
||||
}
|
||||
}
|
||||
user_account { keys = [var.ssh_public_key] }
|
||||
}
|
||||
|
||||
operating_system {
|
||||
template_file_id = "local:vztmpl/debian-12-standard_amd64.tar.zst"
|
||||
type = "debian"
|
||||
}
|
||||
|
||||
features {
|
||||
nesting = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_container" "git0" {
|
||||
vm_id = 103
|
||||
node_name = "pve0"
|
||||
unprivileged = true
|
||||
started = true
|
||||
|
||||
cpu { cores = 2 }
|
||||
memory { dedicated = 1024 }
|
||||
|
||||
disk {
|
||||
datastore_id = "local"
|
||||
size = 8
|
||||
}
|
||||
|
||||
network_interface {
|
||||
name = "eth0"
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 10
|
||||
}
|
||||
|
||||
initialization {
|
||||
hostname = "git0"
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = "10.0.10.13/24"
|
||||
gateway = "10.0.10.1"
|
||||
}
|
||||
}
|
||||
user_account { keys = [var.ssh_public_key] }
|
||||
}
|
||||
|
||||
operating_system {
|
||||
template_file_id = "local:vztmpl/debian-12-standard_amd64.tar.zst"
|
||||
type = "debian"
|
||||
}
|
||||
|
||||
features {
|
||||
nesting = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_container" "storage0" {
|
||||
vm_id = 104
|
||||
node_name = "pve0"
|
||||
unprivileged = false
|
||||
started = true
|
||||
|
||||
cpu { cores = 2 }
|
||||
memory { dedicated = 1024 }
|
||||
|
||||
disk {
|
||||
datastore_id = "local"
|
||||
size = 4
|
||||
}
|
||||
|
||||
network_interface {
|
||||
name = "eth0"
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 10
|
||||
}
|
||||
|
||||
initialization {
|
||||
hostname = "storage0"
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = "10.0.10.14/24"
|
||||
gateway = "10.0.10.1"
|
||||
}
|
||||
}
|
||||
user_account { keys = [var.ssh_public_key] }
|
||||
}
|
||||
|
||||
operating_system {
|
||||
template_file_id = "local:vztmpl/alpine-3.24-default_20260714_amd64.tar.xz"
|
||||
type = "alpine"
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
ignore_changes = [mount_point]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_container" "registry0" {
|
||||
vm_id = 105
|
||||
node_name = "pve0"
|
||||
unprivileged = true
|
||||
started = true
|
||||
|
||||
cpu { cores = 2 }
|
||||
memory { dedicated = 1024 }
|
||||
|
||||
disk {
|
||||
datastore_id = "local"
|
||||
size = 8
|
||||
}
|
||||
|
||||
network_interface {
|
||||
name = "eth0"
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 10
|
||||
}
|
||||
|
||||
initialization {
|
||||
hostname = "registry0"
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = "10.0.10.15/24"
|
||||
gateway = "10.0.10.1"
|
||||
}
|
||||
}
|
||||
user_account { keys = [var.ssh_public_key] }
|
||||
}
|
||||
|
||||
operating_system {
|
||||
template_file_id = "local:vztmpl/debian-12-standard_amd64.tar.zst"
|
||||
type = "debian"
|
||||
}
|
||||
|
||||
features {
|
||||
nesting = true
|
||||
}
|
||||
lifecycle {
|
||||
ignore_changes = [mount_point]
|
||||
}
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# TALOS KUBERNETES CLUSTER
|
||||
# ==============================================================================
|
||||
|
||||
resource "proxmox_virtual_environment_vm" "talos_master_1" {
|
||||
vm_id = 201
|
||||
name = "talos-master-1"
|
||||
node_name = "pve0"
|
||||
started = true
|
||||
|
||||
cpu {
|
||||
cores = 2
|
||||
type = "host"
|
||||
units = 2048
|
||||
}
|
||||
|
||||
memory {
|
||||
dedicated = 2560
|
||||
}
|
||||
|
||||
disk {
|
||||
datastore_id = "astra"
|
||||
file_format = "raw"
|
||||
interface = "virtio0"
|
||||
size = 20
|
||||
}
|
||||
|
||||
cdrom {
|
||||
file_id = var.talos_iso_file_id
|
||||
interface = "ide2"
|
||||
}
|
||||
|
||||
boot_order = ["virtio0", "ide2"]
|
||||
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 20
|
||||
model = "virtio"
|
||||
mac_address = "BC:24:11:71:B6:82"
|
||||
}
|
||||
|
||||
operating_system {
|
||||
type = "l26"
|
||||
}
|
||||
|
||||
agent {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_vm" "talos_worker_1" {
|
||||
vm_id = 202
|
||||
name = "talos-worker-1"
|
||||
node_name = "pve0"
|
||||
started = true
|
||||
|
||||
cpu {
|
||||
cores = 4
|
||||
type = "host"
|
||||
units = 1024
|
||||
}
|
||||
|
||||
memory {
|
||||
dedicated = 10240
|
||||
}
|
||||
|
||||
disk {
|
||||
datastore_id = "astra"
|
||||
file_format = "raw"
|
||||
interface = "virtio0"
|
||||
size = 100
|
||||
}
|
||||
|
||||
cdrom {
|
||||
file_id = var.talos_iso_file_id
|
||||
interface = "ide2"
|
||||
}
|
||||
|
||||
boot_order = ["virtio0", "ide2"]
|
||||
|
||||
# eth0: K8S Overlay
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 20
|
||||
model = "virtio"
|
||||
mac_address = "BC:24:11:12:C5:1B"
|
||||
}
|
||||
|
||||
# eth1: LAN_CLIENTS (L2 Fast-Path)
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 30
|
||||
model = "virtio"
|
||||
}
|
||||
|
||||
operating_system {
|
||||
type = "l26"
|
||||
}
|
||||
|
||||
agent {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_vm" "talos_worker_2" {
|
||||
vm_id = 203
|
||||
name = "talos-worker-2"
|
||||
node_name = "pve0"
|
||||
started = true
|
||||
|
||||
cpu {
|
||||
cores = 4
|
||||
type = "host"
|
||||
units = 1024
|
||||
}
|
||||
|
||||
memory {
|
||||
dedicated = 10240
|
||||
}
|
||||
|
||||
disk {
|
||||
datastore_id = "astra"
|
||||
file_format = "raw"
|
||||
interface = "virtio0"
|
||||
size = 100
|
||||
}
|
||||
|
||||
cdrom {
|
||||
file_id = var.talos_iso_file_id
|
||||
interface = "ide2"
|
||||
}
|
||||
|
||||
boot_order = ["virtio0", "ide2"]
|
||||
|
||||
# eth0: K8S Overlay
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 20
|
||||
model = "virtio"
|
||||
mac_address = "BC:24:11:EF:1A:D4"
|
||||
}
|
||||
|
||||
# eth1: LAN_CLIENTS (L2 Fast-Path)
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 30
|
||||
model = "virtio"
|
||||
}
|
||||
|
||||
operating_system {
|
||||
type = "l26"
|
||||
}
|
||||
|
||||
agent {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
29
tofu/providers.tf
Normal file
29
tofu/providers.tf
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
terraform {
|
||||
required_providers {
|
||||
proxmox = {
|
||||
source = "bpg/proxmox"
|
||||
version = "0.73.0"
|
||||
}
|
||||
vault = {
|
||||
source = "hashicorp/vault"
|
||||
version = "~> 4.2"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "~> 3.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "proxmox" {
|
||||
insecure = true
|
||||
ssh {
|
||||
agent = true
|
||||
username = "root"
|
||||
}
|
||||
}
|
||||
|
||||
provider "vault" {
|
||||
address = "http://10.0.10.12:8200"
|
||||
skip_tls_verify = true
|
||||
}
|
||||
211
tofu/secrets.tf
Normal file
211
tofu/secrets.tf
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
resource "vault_mount" "secret" {
|
||||
path = "secret"
|
||||
type = "kv-v2"
|
||||
description = "Primary KV v2 secrets store"
|
||||
}
|
||||
|
||||
locals {
|
||||
pve_token_parts = split("=", var.proxmox_api_token)
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "proxmox_csi" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "proxmox-csi"
|
||||
data_json = jsonencode({
|
||||
token_id = local.pve_token_parts[0]
|
||||
token_secret = local.pve_token_parts[1]
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "postgres_password" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "postgres" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "postgres"
|
||||
data_json = jsonencode({
|
||||
POSTGRES_PASSWORD = random_password.postgres_password.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "sure_db_password" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "random_password" "sure_secret_key_base" {
|
||||
length = 64
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "sure" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "sure"
|
||||
data_json = jsonencode({
|
||||
DB_PASSWORD = random_password.sure_db_password.result
|
||||
SECRET_KEY_BASE = random_password.sure_secret_key_base.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "authentik_secret_key" {
|
||||
length = 50
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "random_password" "authentik_db_password" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "authentik" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "authentik"
|
||||
data_json = jsonencode({
|
||||
secret_key = random_password.authentik_secret_key.result
|
||||
postgresql_password = random_password.authentik_db_password.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "immich_db_password" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "immich" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "immich"
|
||||
data_json = jsonencode({
|
||||
DB_PASSWORD = random_password.immich_db_password.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "paperless_db_password" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "random_password" "paperless_secret_key" {
|
||||
length = 64
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "paperless" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "paperless"
|
||||
data_json = jsonencode({
|
||||
PAPERLESS_DBPASS = random_password.paperless_db_password.result
|
||||
PAPERLESS_SECRET_KEY = random_password.paperless_secret_key.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "netbox_db_password" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "random_password" "netbox_secret_key" {
|
||||
length = 50
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "netbox" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "netbox"
|
||||
data_json = jsonencode({
|
||||
DB_PASSWORD = random_password.netbox_db_password.result
|
||||
SECRET_KEY = random_password.netbox_secret_key.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "printstash_db_password" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "printstash" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "printstash"
|
||||
data_json = jsonencode({
|
||||
DB_PASSWORD = random_password.printstash_db_password.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "vaultwarden" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "vaultwarden"
|
||||
data_json = jsonencode({
|
||||
ADMIN_TOKEN = var.vaultwarden_admin_token
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "searxng_secret" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "searxng" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "searxng"
|
||||
data_json = jsonencode({
|
||||
SEARXNG_SECRET = random_password.searxng_secret.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "homebox_pepper" {
|
||||
length = 48
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "homebox" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "homebox"
|
||||
data_json = jsonencode({
|
||||
HBOX_AUTH_API_KEY_PEPPER = random_password.homebox_pepper.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "invidious_db_password" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "random_password" "invidious_hmac_key" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "random_password" "invidious_companion_key" {
|
||||
length = 16
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "invidious" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "invidious"
|
||||
data_json = jsonencode({
|
||||
DB_PASSWORD = random_password.invidious_db_password.result
|
||||
HMAC_KEY = random_password.invidious_hmac_key.result
|
||||
COMPANION_KEY = random_password.invidious_companion_key.result
|
||||
})
|
||||
}
|
||||
|
||||
resource "random_password" "karakeep_secret_key" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "random_password" "karakeep_meili_key" {
|
||||
length = 32
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "vault_kv_secret_v2" "karakeep" {
|
||||
mount = vault_mount.secret.path
|
||||
name = "karakeep"
|
||||
data_json = jsonencode({
|
||||
NEXTAUTH_SECRET = random_password.karakeep_secret_key.result
|
||||
MEILI_MASTER_KEY = random_password.karakeep_meili_key.result
|
||||
})
|
||||
}
|
||||
16
tofu/variables.tf
Normal file
16
tofu/variables.tf
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
variable "ssh_public_key" {
|
||||
type = string
|
||||
description = "Публичный SSH-ключ для доступа к ВМ и LXC"
|
||||
}
|
||||
|
||||
variable "proxmox_api_token" {
|
||||
type = string
|
||||
description = "Proxmox API Token формата USER@REALM!TOKENID=UUID"
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "vaultwarden_admin_token" {
|
||||
type = string
|
||||
description = "Vaultwarden Admin Argon2 hash from KeePassXC"
|
||||
sensitive = true
|
||||
}
|
||||
Loading…
Reference in a new issue