Compare commits
361 Commits
Author | SHA1 | Date | |
---|---|---|---|
5e0393823d | |||
78320a8ea4 | |||
03ce47320c | |||
8641bd50e1 | |||
9d7a8029c1 | |||
9c2bce3fab | |||
c248edfc52 | |||
1bc46d957a | |||
8866434590 | |||
1c783dbdfe | |||
f5a180f019 | |||
98c547ebdf | |||
fc5bce0757 | |||
2a58439ab5 | |||
79648879ab | |||
9a76c9efef | |||
52b0ec3bb6 | |||
cf43d32d06 | |||
03dc79c895 | |||
fafbb246ff | |||
e99c5272cc | |||
64b58230e6 | |||
95ca3f40d0 | |||
534bad2a03 | |||
58c483a051 | |||
84d7a68088 | |||
8e8dbc3e65 | |||
77c7c6b36c | |||
505a6b5e8d | |||
1307864afc | |||
c5743a2578 | |||
bd67c60575 | |||
3e8c03904d | |||
408f526239 | |||
c478ba4278 | |||
9ee660cb6d | |||
2235a00f3b | |||
1f8014e740 | |||
bc620987b7 | |||
7477cb7227 | |||
6906623fda | |||
5547241d11 | |||
81093cedfb | |||
7b41d29eb8 | |||
90b7740343 | |||
e88c7c250d | |||
ed83ab0382 | |||
3cfbda7a27 | |||
85c626c96f | |||
634d63c26c | |||
205388f283 | |||
bdfde48bec | |||
9af55580e7 | |||
b9c35bf18f | |||
e7f740a2d9 | |||
57efee14e9 | |||
c711c25737 | |||
24122c2a3e | |||
13121862ec | |||
28da3f425b | |||
2d59886378 | |||
da0f52dab3 | |||
beac302a53 | |||
5edcb86e7e | |||
3dcd4c44b3 | |||
e6653f6495 | |||
a9a919b8f2 | |||
cc66bfdbcb | |||
b02050112e | |||
d5c2a0d185 | |||
6a3ae49d8e | |||
75ee09d7e6 | |||
8b90aa0d74 | |||
62e120ce51 | |||
5fb510202d | |||
64a085ef80 | |||
f2f415aeac | |||
bb291b1f01 | |||
056eac976c | |||
198f96f3f7 | |||
6b5adbdf39 | |||
77ef4b4167 | |||
b35b8cecd5 | |||
b9dfeff6d8 | |||
2ff954b4b5 | |||
2528dafcc6 | |||
0e168376b8 | |||
a16dc204fe | |||
93d340c182 | |||
37ee67b2e6 | |||
35dfeb3093 | |||
0a2eace3dd | |||
6fe1b200f2 | |||
c5d5ab42b8 | |||
efe7864cc9 | |||
9ba74ce698 | |||
4fe3d46d5f | |||
cf8bde7920 | |||
bc87688f1a | |||
3491c1f679 | |||
7b019e0787 | |||
0f19e2433f | |||
c01d45c7a2 | |||
d07afe2319 | |||
b025e4a87e | |||
9be16fef1f | |||
c26da678b3 | |||
6b9533ef71 | |||
0bd995ec2b | |||
0d340f3349 | |||
bcad131aa7 | |||
cda2842f8f | |||
9544222961 | |||
7bc4ae1f8b | |||
1a3c096b65 | |||
25e533287d | |||
7e87002be2 | |||
ab6906e989 | |||
ca55209316 | |||
1b49f015c5 | |||
eb25138675 | |||
69a0f760b4 | |||
3fcedaddb7 | |||
bb34b434b8 | |||
36cdb8f41b | |||
cdd4e9b5d5 | |||
f06e90ab0d | |||
2d733b278c | |||
b218633c2c | |||
e21ec11eb5 | |||
d6f9c2a7e4 | |||
891cfa7b2d | |||
c11b8e157b | |||
0d208b7394 | |||
9b347880cc | |||
a0185d9642 | |||
f2f5f4407c | |||
0b3d3caff6 | |||
52abd94a38 | |||
0391fd95ad | |||
df1ae60936 | |||
a2d33ac309 | |||
1b48892172 | |||
48a48bb080 | |||
bd2c5ca3db | |||
48074bdc39 | |||
2f3fc87f12 | |||
369802cacc | |||
0c3f98d5c3 | |||
b97cfb68ad | |||
d83591cfd4 | |||
f80eccdfa2 | |||
5fe30d005b | |||
ad439d48f3 | |||
df4737655a | |||
b29f405090 | |||
cf90248430 | |||
72a108753b | |||
8dd00c1249 | |||
edeb6cf444 | |||
2bd939e651 | |||
ea8ca478c6 | |||
769965ae6b | |||
f5898b0283 | |||
cdba6aa24f | |||
50447b9a7d | |||
08f92f8ba5 | |||
b13e31d9f8 | |||
a57e87d21f | |||
2efc7f8c2f | |||
7aa5b800ba | |||
013dd8248b | |||
f6dd3f4284 | |||
4a7bff7611 | |||
b4a6901687 | |||
d5078b24da | |||
e2c35a82a9 | |||
50507b2aa8 | |||
0cfd052a6e | |||
1715b58ca9 | |||
440c0b0c4c | |||
47da10febf | |||
0a8395e8fa | |||
05c367e531 | |||
32b5e420bc | |||
9d8aa49b31 | |||
dcb9f7d26f | |||
64d61d69a1 | |||
92e42b5605 | |||
b62029be0a | |||
ddeb8fffbc | |||
41c9d3d6f6 | |||
02959c7673 | |||
3e0533954f | |||
df5ed00f05 | |||
0a5480129e | |||
946873e5ad | |||
d8f8884cb8 | |||
e63327428f | |||
a2d24e03cd | |||
f66bd95fbb | |||
fa0da05343 | |||
2844493fa1 | |||
4b94f66786 | |||
c2632ee7c0 | |||
f333031c25 | |||
254ef01de9 | |||
b5ab68e6f3 | |||
8f6bed297c | |||
882b93a4c5 | |||
0d37652447 | |||
a52c2bc6c7 | |||
70098930f8 | |||
e7c985d276 | |||
0ea9da3a53 | |||
ac29343d96 | |||
f8478ae6c9 | |||
f0d31ff13c | |||
c33f877af8 | |||
b9fb2d4b07 | |||
6524631a53 | |||
10a9689eef | |||
9b11ad9a69 | |||
72c30d4d74 | |||
2e7dc0315e | |||
744466bf07 | |||
d0641f8edf | |||
cb73e2b205 | |||
486df58bac | |||
b75f8fce7b | |||
df062000e7 | |||
2b91b6dc8f | |||
85db434c1f | |||
0a7ad7a9dc | |||
b0c1aca497 | |||
60a4051988 | |||
0ceb513216 | |||
9d5aeeec96 | |||
6dbe0f7f45 | |||
eae5b201b6 | |||
532d7f9a4c | |||
88e91e5e5d | |||
a90b3bbdbe | |||
cdbd6a9cb3 | |||
2a1a7fb6b7 | |||
8650ab973a | |||
acc80868f9 | |||
f606e0a17e | |||
44467d1075 | |||
8b0495c6c8 | |||
2df43584cf | |||
2c128b25f3 | |||
1df5545835 | |||
d4cb91d58d | |||
48322d9a78 | |||
73e9977d41 | |||
5dc0e4bcaf | |||
5169aecc6d | |||
69c8322d50 | |||
f11fad30a5 | |||
a5efe0c21b | |||
30766cce39 | |||
33ec66346b | |||
8d63c50ffb | |||
cf0a415179 | |||
27fd60d84d | |||
0a84fd04bc | |||
1c14430c99 | |||
f75d149f32 | |||
bbc8ba5c6b | |||
973388e109 | |||
42054d8fa6 | |||
4122d92f78 | |||
fb25b52e7a | |||
fb6a899a26 | |||
8cbc9145c0 | |||
7d8bc45090 | |||
87d97ac891 | |||
485bc22e78 | |||
28564b6130 | |||
c38ba8589a | |||
c7f85bd985 | |||
f17dec7b57 | |||
a748adbab0 | |||
747d5ef0e7 | |||
8e3fbcedb9 | |||
f1098d6448 | |||
08d0e93638 | |||
74ce30c3c1 | |||
6f94b4ed67 | |||
98ea2a1ca0 | |||
9204f3c7f0 | |||
d8307935f5 | |||
9f5752c66b | |||
5fb0e0841e | |||
00697ebb02 | |||
f31569ad56 | |||
46dc44aca4 | |||
c9a892e377 | |||
4430b3570e | |||
8679cc1635 | |||
65cb6afaf9 | |||
ee68310e58 | |||
73e7b7063f | |||
6201aaa87e | |||
f655488927 | |||
fda97b8d01 | |||
3ebb616219 | |||
3248f2817b | |||
33fea63b5f | |||
bc354ba041 | |||
d501da4c90 | |||
437b5ce72e | |||
2f9a4df668 | |||
4f7c41a7a5 | |||
24461d4c6f | |||
e0fe3327f0 | |||
a70ad9d5a6 | |||
5228e7c7fb | |||
882fe7e29c | |||
f41bdb7dd0 | |||
208f90e7bf | |||
20bb6ba7aa | |||
de2dae3686 | |||
a7f9351728 | |||
36d00300c3 | |||
19d5321731 | |||
3a95fb46db | |||
f8555f0900 | |||
3a8cca53f3 | |||
9fe63d03d9 | |||
5341cb1c8b | |||
f46cb72681 | |||
2f9d0533e0 | |||
bac0b28f68 | |||
061c375652 | |||
15ea178e8e | |||
1811a851ab | |||
6419f135a1 | |||
0d9d2c7d21 | |||
b0785b210f | |||
bd35cb1265 | |||
fd92573c16 | |||
03fd68b4f7 | |||
0a798aa5a7 | |||
19031834fb | |||
b92917329f | |||
1ef4b988ac | |||
bbe5bfaba4 | |||
290b8885b7 | |||
acdccbc057 | |||
e0c8d1f3c1 | |||
976f8f9e4e | |||
66db9fbd58 | |||
54d479ee9f | |||
91c2ff6345 | |||
7ec6f38c80 | |||
fd731971d3 | |||
7bed73b9a7 | |||
b9aec2a3c4 | |||
fc86b974a7 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -49,3 +49,5 @@ vault-keys.json
|
||||
nomad_bootstrap.json
|
||||
consul_values.yml
|
||||
vault_hashi_vault_values.yml
|
||||
vault_*.yml
|
||||
ansible_playbooks/vars/nomad_vars.yml
|
||||
|
@ -18,9 +18,17 @@ repos:
|
||||
- id: check-added-large-files
|
||||
- id: check-merge-conflict
|
||||
- id: end-of-file-fixer
|
||||
exclude: "^ansible_playbooks/vars/nomad_vars.sample.yml$"
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/Yelp/detect-secrets
|
||||
rev: v1.4.0
|
||||
hooks:
|
||||
- id: detect-secrets
|
||||
args: ['--baseline', '.secrets-baseline']
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: variable-sample
|
||||
name: generate variable sample file
|
||||
language: system
|
||||
entry: bash -c 'venv/bin/python scripts/nomad_vars.py print > ./ansible_playbooks/vars/nomad_vars.sample.yml'
|
||||
types: [file]
|
||||
|
@ -113,41 +113,33 @@
|
||||
{
|
||||
"path": "detect_secrets.filters.regex.should_exclude_secret",
|
||||
"pattern": [
|
||||
"(\\${.*}|from_env|fake|!secret)"
|
||||
"(\\${.*}|from_env|fake|!secret|VALUE)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"results": {
|
||||
"ansible_playbooks/vars/vault_hashi_vault_values.example.yml": [
|
||||
"core/authelia.yml": [
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "ansible_playbooks/vars/vault_hashi_vault_values.example.yml",
|
||||
"hashed_secret": "f2baa52d02ca888455ce47823f47bf372d5eecb3",
|
||||
"filename": "core/authelia.yml",
|
||||
"hashed_secret": "7cb6efb98ba5972a9b5090dc2e517fe14d12cb04",
|
||||
"is_verified": false,
|
||||
"line_number": 8,
|
||||
"line_number": 54,
|
||||
"is_secret": false
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "ansible_playbooks/vars/vault_hashi_vault_values.example.yml",
|
||||
"hashed_secret": "18960546905b75c869e7de63961dc185f9a0a7c9",
|
||||
"filename": "core/authelia.yml",
|
||||
"hashed_secret": "a32b08d97b1615dc27f58b6b17f67624c04e2c4f",
|
||||
"is_verified": false,
|
||||
"line_number": 10,
|
||||
"is_secret": false
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "ansible_playbooks/vars/vault_hashi_vault_values.example.yml",
|
||||
"hashed_secret": "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33",
|
||||
"is_verified": false,
|
||||
"line_number": 22,
|
||||
"line_number": 201,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
"core/metrics/grafana/grafana.ini": [
|
||||
"core/grafana/grafana.ini": [
|
||||
{
|
||||
"type": "Basic Auth Credentials",
|
||||
"filename": "core/metrics/grafana/grafana.ini",
|
||||
"filename": "core/grafana/grafana.ini",
|
||||
"hashed_secret": "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4",
|
||||
"is_verified": false,
|
||||
"line_number": 78,
|
||||
@ -155,7 +147,7 @@
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "core/metrics/grafana/grafana.ini",
|
||||
"filename": "core/grafana/grafana.ini",
|
||||
"hashed_secret": "55ebda65c08313526e7ba08ad733e5ebea9900bd",
|
||||
"is_verified": false,
|
||||
"line_number": 109,
|
||||
@ -163,7 +155,7 @@
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "core/metrics/grafana/grafana.ini",
|
||||
"filename": "core/grafana/grafana.ini",
|
||||
"hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997",
|
||||
"is_verified": false,
|
||||
"line_number": 151,
|
||||
@ -171,7 +163,7 @@
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "core/metrics/grafana/grafana.ini",
|
||||
"filename": "core/grafana/grafana.ini",
|
||||
"hashed_secret": "10bea62ff1e1a7540dc7a6bc10f5fa992349023f",
|
||||
"is_verified": false,
|
||||
"line_number": 154,
|
||||
@ -179,7 +171,7 @@
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "core/metrics/grafana/grafana.ini",
|
||||
"filename": "core/grafana/grafana.ini",
|
||||
"hashed_secret": "5718bce97710e6be87ea160b36eaefb5032857d3",
|
||||
"is_verified": false,
|
||||
"line_number": 239,
|
||||
@ -187,31 +179,13 @@
|
||||
},
|
||||
{
|
||||
"type": "Secret Keyword",
|
||||
"filename": "core/metrics/grafana/grafana.ini",
|
||||
"filename": "core/grafana/grafana.ini",
|
||||
"hashed_secret": "10aed9d7ebef778a9b3033dba3f7813b639e0d50",
|
||||
"is_verified": false,
|
||||
"line_number": 252,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
"core/syslogng.nomad": [
|
||||
{
|
||||
"type": "Base64 High Entropy String",
|
||||
"filename": "core/syslogng.nomad",
|
||||
"hashed_secret": "298b5925fe7c7458cb8a12a74621fdedafea5ad6",
|
||||
"is_verified": false,
|
||||
"line_number": 159,
|
||||
"is_secret": false
|
||||
},
|
||||
{
|
||||
"type": "Base64 High Entropy String",
|
||||
"filename": "core/syslogng.nomad",
|
||||
"hashed_secret": "3a1cec2d3c3de7e4da4d99c6731ca696c24b72b4",
|
||||
"is_verified": false,
|
||||
"line_number": 159,
|
||||
"is_secret": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"generated_at": "2022-11-11T21:26:53Z"
|
||||
"generated_at": "2024-08-30T18:12:43Z"
|
||||
}
|
||||
|
@ -1,78 +1,40 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/consul" {
|
||||
version = "2.14.0"
|
||||
hashes = [
|
||||
"h1:lJWOdlqevg6FQLFlfM3tGOsy9yPrjm9/vqkfzVrqT/A=",
|
||||
"h1:xRwktNwLL3Vo43F7v73tfcgbcnjCE2KgCzcNrsQJ1cc=",
|
||||
"zh:06dcca1f76b839af8f86c7b6f65b944003a7a35b30b865b3884f48e2c42f9aee",
|
||||
"zh:16111df6a485e21cee6ca33cb863434baa1ca360c819c8e2af85e465c1361d2b",
|
||||
"zh:26b59c82ac2861b2651c1fa31955c3e7790e3c2d5d097f22aa34d3c294da63cf",
|
||||
"zh:70fd6853099126a602d5ac26caa80214a4a8a38f0cad8a5e3b7bef49923419d3",
|
||||
"zh:7d4f0061d6fb86e0a5639ed02381063b868245082ec4e3a461bcda964ed00fcc",
|
||||
"zh:a48cbf57d6511922362d5b0f76f449fba7a550c9d0702635fabb43b4f0a09fc0",
|
||||
"zh:bb54994a53dd8e1ff84ca50742ce893863dc166fd41b91d951f4cb89fe6a6bc0",
|
||||
"zh:bc61b19ee3c8d55a9915a3ad84203c87bfd0d57eca8eec788524b14e8b67f090",
|
||||
"zh:cbe3238e756ada23c1e7c97c42a5c72bf810dc5bd1265c9f074c3e739d1090b0",
|
||||
"zh:e30198054239eab46493e59956b9cd8c376c3bbd9515ac102a96d1fbd32e423f",
|
||||
"zh:e74365dba529a0676107e413986d7be81c2125c197754ce69e3e89d8daa53153",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/external" {
|
||||
version = "2.2.2"
|
||||
hashes = [
|
||||
"h1:e7RpnZ2PbJEEPnfsg7V0FNwbfSk0/Z3FdrLsXINBmDY=",
|
||||
"zh:0b84ab0af2e28606e9c0c1289343949339221c3ab126616b831ddb5aaef5f5ca",
|
||||
"zh:10cf5c9b9524ca2e4302bf02368dc6aac29fb50aeaa6f7758cce9aa36ae87a28",
|
||||
"zh:56a016ee871c8501acb3f2ee3b51592ad7c3871a1757b098838349b17762ba6b",
|
||||
"zh:719d6ef39c50e4cffc67aa67d74d195adaf42afcf62beab132dafdb500347d39",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:7fbfc4d37435ac2f717b0316f872f558f608596b389b895fcb549f118462d327",
|
||||
"zh:8ac71408204db606ce63fe8f9aeaf1ddc7751d57d586ec421e62d440c402e955",
|
||||
"zh:a4cacdb06f114454b6ed0033add28006afa3f65a0ea7a43befe45fc82e6809fb",
|
||||
"zh:bb5ce3132b52ae32b6cc005bc9f7627b95259b9ffe556de4dad60d47d47f21f0",
|
||||
"zh:bb60d2976f125ffd232a7ccb4b3f81e7109578b23c9c6179f13a11d125dca82a",
|
||||
"zh:f9540ecd2e056d6e71b9ea5f5a5cf8f63dd5c25394b9db831083a9d4ea99b372",
|
||||
"zh:ffd998b55b8a64d4335a090b6956b4bf8855b290f7554dd38db3302de9c41809",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "1.4.16"
|
||||
version = "2.2.0"
|
||||
hashes = [
|
||||
"h1:PQxNPNmMVOErxryTWIJwr22k95DTSODmgRylqjc2TjI=",
|
||||
"h1:tyfjD/maKzb0RxxD9KWgLnkJu9lnYziYsQgGw85Giz8=",
|
||||
"zh:0d4fbb7030d9caac3b123e60afa44f50c83cc2a983e1866aec7f30414abe7b0e",
|
||||
"zh:0db080228e07c72d6d8ca8c45249d6f97cd0189fce82a77abbdcd49a52e57572",
|
||||
"zh:0df88393271078533a217654b96f0672c60eb59570d72e6aefcb839eea87a7a0",
|
||||
"zh:2883b335bb6044b0db6a00e602d6926c047c7f330294a73a90d089f98b24d084",
|
||||
"zh:390158d928009a041b3a182bdd82376b50530805ae92be2b84ed7c3b0fa902a0",
|
||||
"zh:7169b8f8df4b8e9659c49043848fd5f7f8473d0471f67815e8b04980f827f5ef",
|
||||
"zh:9417ee1383b1edd137024882d7035be4dca51fb4f725ca00ed87729086ec1755",
|
||||
"zh:a22910b5a29eeab5610350700b4899267c1b09b66cf21f7e4d06afc61d425800",
|
||||
"zh:a6185c9cd7aa458cd81861058ba568b6411fbac344373a20155e20256f4a7557",
|
||||
"zh:b6260ca9f034df1b47905b4e2a9c33b67dbf77224a694d5b10fb09ae92ffad4c",
|
||||
"zh:d87c12a6a7768f2b6c2a59495c7dc00f9ecc52b1b868331d4c284f791e278a1e",
|
||||
"h1:BAjqzVkuXxHtRKG+l9unaZJPk2kWZpSTCEcQPRcl2so=",
|
||||
"zh:052f909d25121e93dc799290216292fca67943ccde12ba515068b838a6ff8c66",
|
||||
"zh:20e29aeb9989f7a1e04bb4093817c7acc4e1e737bb21a3066f3ea46f2001feff",
|
||||
"zh:2326d101ef427599b72cce30c0e0c1d18ae783f1a897c20f2319fbf54bab0a61",
|
||||
"zh:3420cbe4fd19cdc96d715d0ae8e79c272608023a76033bbf582c30637f6d570f",
|
||||
"zh:41ec570f87f578f1c57655e2e4fbdb9932d94cf92dc9cd11828cccedf36dd4a4",
|
||||
"zh:5f90dcc58e3356ffead82ea211ecb4a2d7094d3c2fbd14ff85527c3652a595a2",
|
||||
"zh:64aaa48609d2db868fcfd347490df0e12c6c3fcb8e4f12908c5d52b1a0adf73f",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:86b4923e10e6ba407d1d2aab83740b702058e8b01460af4f5f0e4008f40e492c",
|
||||
"zh:ae89dcba33097af33a306344d20e4e25181f15dcc1a860b42db5b7199a97c6a6",
|
||||
"zh:ce56d68cdfba60891765e94f9c0bf69eddb985d44d97db9f91874bea027f08e2",
|
||||
"zh:e993bcde5dbddaedf3331e3014ffab904f98ab0f5e8b5d6082b7ca5083e0a2f1",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/vault" {
|
||||
version = "3.3.1"
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.6.0"
|
||||
hashes = [
|
||||
"h1:SOTmxGynxFf1hECFq0/FGujGQZNktePze/4mfdR/iiU=",
|
||||
"h1:i7EC2IF0KParI+JPA5ZtXJrAn3bAntW5gEMLvOXwpW4=",
|
||||
"zh:3e1866037f43c1083ff825dce2a9e3853c757bb0121c5ae528ee3cf3f99b4113",
|
||||
"zh:49636cc5c4939134e098c4ec0163c41fae103f24d7e1e8fc0432f8ad93d596a0",
|
||||
"zh:5258a7001719c4aeb84f4c4da7115b795da4794754938a3c4176a4b578fe93a1",
|
||||
"zh:7461738691e2e8ea91aba73d4351cfbc30fcaedcf0e332c9d35ef215f93aa282",
|
||||
"zh:815529478e33a6727273b08340a4c62c9aeb3da02abf8f091bb4f545c8451fce",
|
||||
"zh:8e6fede9f5e25b507faf6cacd61b997035b8b62859245861149ddb2990ada8eb",
|
||||
"zh:9acc2387084b9c411e264c4351633bc82f9c4e420f8e6bbad9f87b145351f929",
|
||||
"zh:b9e4af3b06386ceed720f0163a1496088c154aa1430ae072c525ffefa4b37891",
|
||||
"zh:c7d5dfb8f8536694db6740e2a4afd2d681b60b396ded469282524c62ce154861",
|
||||
"zh:d0850be710c6fd682634a2f823beed0164231cc873b1dc09038aa477c926f57c",
|
||||
"zh:e90c2cba9d89db5eab295b2f046f24a53f23002bcfe008633d398fb3fa16d941",
|
||||
"h1:R5Ucn26riKIEijcsiOMBR3uOAjuOMfI1x7XvH4P6B1w=",
|
||||
"zh:03360ed3ecd31e8c5dac9c95fe0858be50f3e9a0d0c654b5e504109c2159287d",
|
||||
"zh:1c67ac51254ba2a2bb53a25e8ae7e4d076103483f55f39b426ec55e47d1fe211",
|
||||
"zh:24a17bba7f6d679538ff51b3a2f378cedadede97af8a1db7dad4fd8d6d50f829",
|
||||
"zh:30ffb297ffd1633175d6545d37c2217e2cef9545a6e03946e514c59c0859b77d",
|
||||
"zh:454ce4b3dbc73e6775f2f6605d45cee6e16c3872a2e66a2c97993d6e5cbd7055",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:91df0a9fab329aff2ff4cf26797592eb7a3a90b4a0c04d64ce186654e0cc6e17",
|
||||
"zh:aa57384b85622a9f7bfb5d4512ca88e61f22a9cea9f30febaa4c98c68ff0dc21",
|
||||
"zh:c4a3e329ba786ffb6f2b694e1fd41d413a7010f3a53c20b432325a94fa71e839",
|
||||
"zh:e2699bc9116447f96c53d55f2a00570f982e6f9935038c3810603572693712d0",
|
||||
"zh:e747c0fd5d7684e5bfad8aa0ca441903f15ae7a98a737ff6aca24ba223207e2c",
|
||||
"zh:f1ca75f417ce490368f047b63ec09fd003711ae48487fba90b4aba2ccf71920e",
|
||||
]
|
||||
}
|
||||
|
52
Makefile
52
Makefile
@ -1,8 +1,16 @@
|
||||
SLEEP_FOR ?= 10
|
||||
VENV ?= venv
|
||||
|
||||
.PHONY: sleep
|
||||
sleep:
|
||||
sleep $(SLEEP_FOR)
|
||||
|
||||
.PHONY: default
|
||||
default: check
|
||||
|
||||
.PHONY: all
|
||||
all: cluster bootstrap-values apply
|
||||
|
||||
.PHONY: cluster
|
||||
cluster: ansible-cluster
|
||||
|
||||
@ -22,8 +30,8 @@ check: $(VENV)
|
||||
$(VENV)/bin/pre-commit run --all-files
|
||||
|
||||
# Creates a new secrets baseline
|
||||
.secrets-baseline: $(VENV)
|
||||
$(VENV)/bin/detect-secrets scan --exclude-secrets '(\$${.*}|from_env|fake|!secret)' > .secrets-baseline
|
||||
.secrets-baseline: $(VENV) Makefile
|
||||
$(VENV)/bin/detect-secrets scan --exclude-secrets '(\$${.*}|from_env|fake|!secret|VALUE)' > .secrets-baseline
|
||||
|
||||
# Audits secrets against baseline
|
||||
.PHONY: secrets-audit
|
||||
@ -51,16 +59,18 @@ ansible-cluster: $(VENV) ansible_galaxy
|
||||
./ansible_playbooks/setup-cluster.yml
|
||||
|
||||
.PHONY: bootstrap-values
|
||||
bootstrap-values: $(VENV) ansible_galaxy
|
||||
env VIRTUAL_ENV=$(VENV) $(VENV)/bin/ansible-playbook -vv \
|
||||
-e "@vault-keys.json" \
|
||||
./ansible_playbooks/bootstrap-values.yml
|
||||
bootstrap-values: $(VENV)
|
||||
env NOMAD_ADDR=http://192.168.2.101:4646 \
|
||||
NOMAD_TOKEN=$(shell jq -r .SecretID nomad_bootstrap.json) \
|
||||
$(VENV)/bin/python ./scripts/nomad_vars.py
|
||||
|
||||
.PHONY: unseal-vault
|
||||
unseal-vault: $(VENV) ansible_galaxy
|
||||
env VIRTUAL_ENV=$(VENV) $(VENV)/bin/ansible-playbook -K -vv \
|
||||
-e "@vault-keys.json" \
|
||||
./ansible_playbooks/unseal-vault.yml
|
||||
.PHONY: recover-nomad
|
||||
recover-nomad: $(VENV)
|
||||
$(VENV)/bin/ansible-playbook -K ./ansible_playbooks/recover-nomad.yaml
|
||||
|
||||
.PHONY: stop-cluster
|
||||
stop-cluster: $(VENV)
|
||||
$(VENV)/bin/ansible-playbook -K ./ansible_playbooks/stop-cluster.yml
|
||||
|
||||
.PHONY: init
|
||||
init:
|
||||
@ -70,10 +80,26 @@ init:
|
||||
plan:
|
||||
@terraform plan \
|
||||
-var "nomad_secret_id=$(shell jq -r .SecretID nomad_bootstrap.json)" \
|
||||
-var "vault_token=$(shell jq -r .root_token vault-keys.json)"
|
||||
|
||||
.PHONY: apply
|
||||
apply:
|
||||
@terraform apply \
|
||||
-auto-approve \
|
||||
-var "nomad_secret_id=$(shell jq -r .SecretID nomad_bootstrap.json)" \
|
||||
-var "vault_token=$(shell jq -r .root_token vault-keys.json)"
|
||||
|
||||
.PHONY: refresh
|
||||
refresh:
|
||||
@terraform refresh \
|
||||
-var "nomad_secret_id=$(shell jq -r .SecretID nomad_bootstrap.json)" \
|
||||
|
||||
.PHONY: destroy
|
||||
destroy:
|
||||
@terraform destroy \
|
||||
-var "nomad_secret_id=$(shell jq -r .SecretID nomad_bootstrap.json)" \
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
env VIRTUAL_ENV=$(VENV) $(VENV)/bin/ansible-playbook -vv \
|
||||
./ansible_playbooks/clear-data.yml
|
||||
find -name "*.tfstate" -exec rm '{}' \;
|
||||
rm -f ./vault-keys.json ./nomad_bootstrap.json
|
||||
|
46
README.md
Normal file
46
README.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Homelab Nomad
|
||||
|
||||
My configuration for creating my home Nomad cluster and deploying services to it.
|
||||
|
||||
This repo is not designed as general purpose templates, but rather to fit my specific needs. That said, I have made an effort for things to be as useful as possible for someone wanting to use or modify this.
|
||||
|
||||
## Running
|
||||
|
||||
make all
|
||||
|
||||
## Design
|
||||
|
||||
Both Ansible and Terraform are used as part of this configuration. All hosts must be reachable over SSH prior to running any of this configuration.
|
||||
|
||||
To begin, Ansible runs a playbook to setup the cluster. This includes installing Nomad, bootstrapping the cluster and ACLs, setting up NFS shares, creating Nomad Host Volumes, and setting up Wesher as a Wireguard mesh between hosts.
|
||||
|
||||
After this is complete, Nomad variables must be set for services to access and configure correctly. This depends on variables to be set based on the sample file.
|
||||
|
||||
Finally, the Terraform configuration can be applied setting up all services deployed on the cluster.
|
||||
|
||||
The configuration of new services is intended to be as templated as possible and to avoid requiring changes in multiple places. For example, most services are configured with a template that provides reverse proxy, DNS records, database tunnels, database bootstrapping, metrics scraping, and authentication. The only real exception is backups, which requires a distinct job file, for now.
|
||||
|
||||
## What does it do?
|
||||
|
||||
* Nomad cluster for scheduling and configuring all services
|
||||
* Blocky DNS servers with integrated ad blocking. This also provides service discovery
|
||||
* Prometheus with autodiscovery of service metrics
|
||||
* Loki and Promtail aggregating logs
|
||||
* Minitor for service availability checks
|
||||
* Grafana providing dashboards, alerting, and log searching
|
||||
* Photoprism for photo management
|
||||
* Remote and shared volumes over NFS
|
||||
* Authelia for OIDC and Proxy based authentication with 2FA
|
||||
* Sonarr and Lidarr for multimedia management
|
||||
* Automated block based backups using Restic
|
||||
|
||||
## Step by step
|
||||
|
||||
1. Update hosts in `ansible_playbooks/ansible_hosts.yml`
|
||||
2. Update `ansible_playbook/setup-cluster.yml`
|
||||
1. Update backup DNS server
|
||||
2. Update NFS shares from NAS
|
||||
3. Update volumes to make sure they are valid paths
|
||||
3. Create `ansible_playbooks/vars/nomad_vars.yml` based on the sample file. TODO: This is quite specific and probably impossible without more documentation
|
||||
4. Run `make all`
|
||||
5. Update your network DNS settings to use the new servers IP addresses
|
@ -1,59 +1,21 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/consul" {
|
||||
version = "2.15.1"
|
||||
hashes = [
|
||||
"h1:PexyQBRLDA+SR+sWlzYBZswry5O5h/tTfj87CaECtLc=",
|
||||
"zh:1806830a3cf103e65e772a7d28fd4df2788c29a029fb2def1326bc777ad107ed",
|
||||
"zh:252be544fb4c9daf09cad7d3776daf5fa66b62740d3ea9d6d499a7b1697c3433",
|
||||
"zh:50985fe02a8e5ae47c75d7c28c911b25d7dc4716cff2ed55ca05889ab77a1f73",
|
||||
"zh:54cf0ec90538703c66937c77e8d72a38d5af47437eb0b8b55eb5836c5d288878",
|
||||
"zh:704f536c621337e06fffef6d5f49ac81f52d249f937250527c12884cb83aefed",
|
||||
"zh:896d8ef6d0b555299f124eb25bce8a17d735da14ef21f07582098d301f47da30",
|
||||
"zh:976277a85b0a0baafe267cc494f766448d1da5b6936ddcb3ce393bd4d22f08d2",
|
||||
"zh:c7faa9a2b11bc45833a3e8e340f22f1ecf01597eaeffa7669234b4549d7dfa85",
|
||||
"zh:caf851ef9c8ce482864badf7058f9278d4537112fa236efd8f1a9315801d9061",
|
||||
"zh:db203435d58b0ac842540861b3307a623423275d85754c171773f3b210ae5b24",
|
||||
"zh:f3d3efac504c9484a025beb919d22b290aa6dbff256f6e86c1f8ce7817e077e5",
|
||||
"zh:f710a37190429045d109edd35de69db3b5f619919c2fa04c77a3a639fea9fd7d",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "1.4.17"
|
||||
version = "1.4.20"
|
||||
hashes = [
|
||||
"h1:iPylWr144mqXvM8NBVMTm+MS6JRhqIihlpJG91GYDyA=",
|
||||
"zh:146f97eacd9a0c78b357a6cfd2cb12765d4b18e9660a75500ee3e748c6eba41a",
|
||||
"zh:2eb89a6e5cee9aea03a96ea9f141096fe3baf219b2700ce30229d2d882f5015f",
|
||||
"zh:3d0f971f79b615c1014c75e2f99f34bd4b4da542ca9f31d5ea7fadc4e9de39c1",
|
||||
"zh:46099a750c752ce05aa14d663a86478a5ad66d95aff3d69367f1d3628aac7792",
|
||||
"zh:71e56006b013dcfe1e4e059b2b07148b44fcd79351ae2c357e0d97e27ae0d916",
|
||||
"zh:74febd25d776688f0558178c2f5a0e6818bbf4cdaa2e160d7049da04103940f0",
|
||||
"h1:M/QVXHPfeySejJZI3I8mBYrL/J9VsbnyF/dKIMlUhXo=",
|
||||
"zh:02989edcebe724fc0aa873b22176fd20074c4f46295e728010711a8fc5dfa72c",
|
||||
"zh:089ba7d19bcf5c6bab3f8b8c5920eb6d78c52cf79bb0c5dfeb411c600e7efcba",
|
||||
"zh:235865a2182ca372bcbf440201a8b8cc0715ad5dbc4de893d99b6f32b5be53ab",
|
||||
"zh:67ea718764f3f344ecc6e027d20c1327b86353c8064aa90da3ec12cec4a88954",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:af18c064a5f0dd5422d6771939274841f635b619ab392c73d5bf9720945fdb85",
|
||||
"zh:c133d7a862079da9f06e301c530eacbd70e9288fa2276ec0704df907270ee328",
|
||||
"zh:c894cf98d239b9f5a4b7cde9f5c836face0b5b93099048ee817b0380ea439c65",
|
||||
"zh:c918642870f0cafdbe4d7dd07c909701fc3ddb47cac8357bdcde1327bf78c11d",
|
||||
"zh:f8f5655099a57b4b9c0018a2d49133771e24c7ff8262efb1ceb140fd224aa9b6",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/vault" {
|
||||
version = "3.7.0"
|
||||
hashes = [
|
||||
"h1:idawLPCbZgHIb+NRLJs4YdIcQgACqYiT5VwQfChkn+w=",
|
||||
"zh:256b82692c560c76ad51414a2c003cadfa10338a9df333dbe22dd14a9ed16f95",
|
||||
"zh:329ed8135a98bd6a000d014e40bc5981c6868cf50eedf454f1a1f72ac463bdf0",
|
||||
"zh:3b32c18b492a6ac8e1ccac40d28cd42a88892ef8f3515291676136e3faac351c",
|
||||
"zh:4c5ea8e80543b36b1999257a41c8b9cde852542251de82a94cff2f9d280ac2ec",
|
||||
"zh:5d968ed305cde7aa3567a943cb2f5f8def54b40a2292b66027b1405a1cf28585",
|
||||
"zh:60226d1a0a496a9a6c1d646800dd7e1bd1c4f5527e7307ff0bca9f4d0b5395e2",
|
||||
"zh:71b11def501c994ee5305f24bd47ebfcca2314c5acca3efcdd209373d0068ac0",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:89be6b5db3be473bfd14422a9abf83245c4b22ce47a8fe463bbebf8e20958ab1",
|
||||
"zh:8f91051d43ae309bb8f3f6a9659f0fd26b1b239faf671c139b4e9ad0d208db05",
|
||||
"zh:b5114983273d3170878f657b92738b2c40953aedeef2e1840588ecaf1bc0827e",
|
||||
"zh:fd56db01c5444dc8ca2e0ad2f13fc4c17735d0fdeb5960e23176fb3f5a5114d3",
|
||||
"zh:8c68c540f0df4980568bdd688c2adec86eda62eb2de154e3db215b16de0a7ae0",
|
||||
"zh:911969c63a69a733be57b96d54c5966c9424e1abec8d5f20038c8cef3a504c65",
|
||||
"zh:a673c92ddc9d47e8d53dcb9b376f1adcb4543488202fc83a3e7eab8677530684",
|
||||
"zh:a94a73eae89fd8c8ebf872013079be41161d3f293f4026c92d45c4c5667dd613",
|
||||
"zh:db6b89f8b696040c0344f00928e4cf6e0a75034421ba14cdcd8a4d23bc865dce",
|
||||
"zh:e512c0b1239e3d66b60d22c2b4de19fea288e492cde90dff9277cc475fd9dbbf",
|
||||
"zh:ef6eccecbdef3bb8ce629cabfb5550c1db5c3e952943dda1786ef6cb470a8c23",
|
||||
]
|
||||
}
|
||||
|
@ -1,6 +1,12 @@
|
||||
namespace "*" {
|
||||
policy = "write"
|
||||
capabilities = ["alloc-node-exec"]
|
||||
|
||||
variables {
|
||||
path "*" {
|
||||
capabilities = ["write", "read", "destroy"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
agent {
|
||||
|
@ -1,6 +1,6 @@
|
||||
resource "nomad_acl_policy" "anon_policy" {
|
||||
name = "anonymous"
|
||||
description = "Anon RO"
|
||||
description = "Anon read only"
|
||||
rules_hcl = file("${path.module}/nomad-anon-policy.hcl")
|
||||
}
|
||||
|
||||
|
17
acls/nomad_roles.tf
Normal file
17
acls/nomad_roles.tf
Normal file
@ -0,0 +1,17 @@
|
||||
resource "nomad_acl_role" "admin" {
|
||||
name = "admin"
|
||||
description = "Nomad administrators"
|
||||
|
||||
policy {
|
||||
name = nomad_acl_policy.admin.name
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_role" "deploy" {
|
||||
name = "deploy"
|
||||
description = "Authorized to conduct deployments and view logs"
|
||||
|
||||
policy {
|
||||
name = nomad_acl_policy.deploy.name
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
# Set up nomad provider in vault for Nomad ACLs
|
||||
resource "nomad_acl_token" "vault" {
|
||||
name = "vault"
|
||||
type = "management"
|
||||
}
|
||||
|
||||
resource "vault_nomad_secret_backend" "config" {
|
||||
backend = "nomad"
|
||||
description = "Nomad ACL"
|
||||
token = nomad_acl_token.vault.secret_id
|
||||
|
||||
default_lease_ttl_seconds = "3600"
|
||||
max_lease_ttl_seconds = "7200"
|
||||
|
||||
ttl = "3600"
|
||||
max_ttl = "7200"
|
||||
}
|
||||
|
||||
# Vault roles generating Nomad tokens
|
||||
resource "vault_nomad_secret_role" "nomad-deploy" {
|
||||
backend = vault_nomad_secret_backend.config.backend
|
||||
role = "nomad-deploy"
|
||||
# Nomad policies
|
||||
policies = ["deploy"]
|
||||
}
|
||||
|
||||
resource "vault_nomad_secret_role" "admin-management" {
|
||||
backend = vault_nomad_secret_backend.config.backend
|
||||
role = "admin-management"
|
||||
type = "management"
|
||||
}
|
||||
|
||||
resource "vault_nomad_secret_role" "admin" {
|
||||
backend = vault_nomad_secret_backend.config.backend
|
||||
role = "admin"
|
||||
# Nomad policies
|
||||
policies = ["admin"]
|
||||
}
|
||||
|
||||
# Nomad Vault token access
|
||||
resource "vault_token_auth_backend_role" "nomad-cluster" {
|
||||
role_name = "nomad-cluster"
|
||||
token_explicit_max_ttl = 0
|
||||
allowed_policies = ["access-tables", "nomad-task"]
|
||||
orphan = true
|
||||
token_period = 259200
|
||||
renewable = true
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
# resource "vault_mount" "db" {
|
||||
# path = "database"
|
||||
# type = "database"
|
||||
# }
|
||||
#
|
||||
# resource "vault_database_secret_backend_connection" "mysql" {
|
||||
# backend = vault_mount.db.path
|
||||
# name = "mysql"
|
||||
# allowed_roles = ["accessdb"]
|
||||
#
|
||||
# mysql {
|
||||
# # How to give access here?
|
||||
# connection_url = "{{username}}:{{password}}@tcp(mysql-server.service.consul:3306)"
|
||||
# username = ""
|
||||
# password = ""
|
||||
# }
|
||||
# }
|
@ -1,38 +1,6 @@
|
||||
# Configure Consul provider
|
||||
provider "consul" {
|
||||
address = var.consul_address
|
||||
}
|
||||
|
||||
# Get Nomad client from Consul
|
||||
data "consul_service" "nomad" {
|
||||
name = "nomad-client"
|
||||
}
|
||||
|
||||
# Get Vault client from Consul
|
||||
data "consul_service" "vault" {
|
||||
name = "vault"
|
||||
tag = "active"
|
||||
}
|
||||
|
||||
locals {
|
||||
# Get Nomad address from Consul
|
||||
nomad_node = data.consul_service.nomad.service[0]
|
||||
nomad_node_address = "http://${local.nomad_node.node_address}:${local.nomad_node.port}"
|
||||
|
||||
# Get Vault address from Consul
|
||||
vault_node = data.consul_service.vault.service[0]
|
||||
vault_node_address = "http://${local.vault_node.node_address}:${local.vault_node.port}"
|
||||
}
|
||||
|
||||
# Configure the Nomad provider
|
||||
provider "nomad" {
|
||||
address = local.nomad_node_address
|
||||
address = var.nomad_address
|
||||
secret_id = var.nomad_secret_id
|
||||
region = "global"
|
||||
}
|
||||
|
||||
# Configure the Vault provider
|
||||
provider "vault" {
|
||||
address = local.vault_node_address
|
||||
token = var.vault_token
|
||||
}
|
||||
|
12
acls/vars.tf
12
acls/vars.tf
@ -1,8 +1,3 @@
|
||||
variable "consul_address" {
|
||||
type = string
|
||||
default = "http://n1.thefij:8500"
|
||||
}
|
||||
|
||||
variable "nomad_secret_id" {
|
||||
type = string
|
||||
description = "Secret ID for ACL bootstrapped Nomad"
|
||||
@ -10,8 +5,7 @@ variable "nomad_secret_id" {
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "vault_token" {
|
||||
type = string
|
||||
sensitive = true
|
||||
default = ""
|
||||
variable "nomad_address" {
|
||||
type = string
|
||||
default = "http://n1.thefij:4646"
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
resource "vault_auth_backend" "userpass" {
|
||||
type = "userpass"
|
||||
|
||||
tune {
|
||||
max_lease_ttl = "1h"
|
||||
listing_visibility = "unauth"
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
resource "vault_policy" "admin" {
|
||||
name = "admin"
|
||||
|
||||
policy = <<EOF
|
||||
path "*" {
|
||||
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "vault_policy" "nomad-deploy" {
|
||||
name = "nomad-deploy"
|
||||
policy = <<EOH
|
||||
path "nomad/creds/nomad-deploy" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
EOH
|
||||
}
|
||||
|
||||
# Policy for clusters
|
||||
resource "vault_policy" "nomad-task" {
|
||||
name = "nomad-task"
|
||||
policy = <<EOH
|
||||
path "kv/data/*" {
|
||||
# Does this need create, update, delete?
|
||||
capabilities = ["create", "read", "update", "delete", "list"]
|
||||
}
|
||||
EOH
|
||||
}
|
||||
|
||||
# Policy for nomad tokens
|
||||
resource "vault_policy" "nomad-server" {
|
||||
name = "nomad-server"
|
||||
policy = <<EOH
|
||||
# Allow creating tokens under "nomad-cluster" token role. The token role name
|
||||
# should be updated if "nomad-cluster" is not used.
|
||||
path "auth/token/create/nomad-cluster" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
|
||||
# Allow looking up "nomad-cluster" token role. The token role name should be
|
||||
# updated if "nomad-cluster" is not used.
|
||||
path "auth/token/roles/nomad-cluster" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
|
||||
# Allow looking up the token passed to Nomad to validate # the token has the
|
||||
# proper capabilities. This is provided by the "default" policy.
|
||||
path "auth/token/lookup-self" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
|
||||
# Allow looking up incoming tokens to validate they have permissions to access
|
||||
# the tokens they are requesting. This is only required if
|
||||
# `allow_unauthenticated` is set to false.
|
||||
path "auth/token/lookup" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
|
||||
# Allow revoking tokens that should no longer exist. This allows revoking
|
||||
# tokens for dead tasks.
|
||||
path "auth/token/revoke-accessor" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
|
||||
# Allow checking the capabilities of our own token. This is used to validate the
|
||||
# token upon startup.
|
||||
path "sys/capabilities-self" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
|
||||
# Allow our own token to be renewed.
|
||||
path "auth/token/renew-self" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
|
||||
# This section grants all access on "secret/*". Further restrictions can be
|
||||
# applied to this broad policy, as shown below.
|
||||
path "kv/data/*" {
|
||||
capabilities = ["create", "read", "update", "delete", "list"]
|
||||
}
|
||||
EOH
|
||||
}
|
@ -1,65 +1,72 @@
|
||||
---
|
||||
all:
|
||||
children:
|
||||
servers:
|
||||
hosts:
|
||||
n1.thefij:
|
||||
nomad_node_role: both
|
||||
nomad_unique_host_volumes:
|
||||
- name: mysql-data
|
||||
path: /srv/volumes/mysql
|
||||
owner: "999"
|
||||
group: "100"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
- name: lldap-data
|
||||
path: /srv/volumes/lldap
|
||||
owner: "root"
|
||||
group: "bin"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
n2.thefij:
|
||||
nomad_node_class: ingress
|
||||
nomad_node_role: both
|
||||
nomad_unique_host_volumes:
|
||||
- name: nextcloud-data
|
||||
path: /srv/volumes/nextcloud
|
||||
owner: "root"
|
||||
group: "bin"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
- name: gitea-data
|
||||
path: /srv/volumes/gitea
|
||||
owner: "root"
|
||||
group: "bin"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
- name: sonarr-data
|
||||
path: /srv/volumes/sonarr
|
||||
owner: "root"
|
||||
group: "bin"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
- name: nzbget-data
|
||||
path: /srv/volumes/nzbget
|
||||
owner: "root"
|
||||
group: "bin"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
# n3.thefij:
|
||||
# nomad_node_class: ingress
|
||||
# nomad_node_role: both
|
||||
# pi3:
|
||||
# nomad_node_role: client
|
||||
pi4:
|
||||
nomad_node_role: both
|
||||
hosts:
|
||||
n1.thefij:
|
||||
nomad_node_class: ingress
|
||||
nomad_reserved_memory: 1024
|
||||
# nomad_meta:
|
||||
# hw_transcode.device: /dev/dri
|
||||
# hw_transcode.type: intel
|
||||
nfs_mounts:
|
||||
- src: 10.50.250.2:/srv/volumes
|
||||
path: /srv/volumes/moxy
|
||||
opts: proto=tcp,rw
|
||||
nomad_unique_host_volumes:
|
||||
- name: mysql-data
|
||||
path: /srv/volumes/mysql
|
||||
owner: "999"
|
||||
group: "100"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
- name: postgres-data
|
||||
path: /srv/volumes/postgres
|
||||
owner: "999"
|
||||
group: "999"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
# n2.thefij:
|
||||
# nomad_node_class: ingress
|
||||
# nomad_reserved_memory: 1024
|
||||
# nfs_mounts:
|
||||
# - src: 10.50.250.2:/srv/volumes
|
||||
# path: /srv/volumes/moxy
|
||||
# opts: proto=tcp,rw
|
||||
# nomad_unique_host_volumes:
|
||||
# - name: nextcloud-data
|
||||
# path: /srv/volumes/nextcloud
|
||||
# owner: "root"
|
||||
# group: "bin"
|
||||
# mode: "0755"
|
||||
# read_only: false
|
||||
pi4:
|
||||
nomad_node_class: ingress
|
||||
nomad_reserved_memory: 512
|
||||
nomad_meta:
|
||||
hw_transcode.device: /dev/video11
|
||||
hw_transcode.type: raspberry
|
||||
qnomad.thefij:
|
||||
ansible_host: 192.168.2.234
|
||||
nomad_reserved_memory: 1024
|
||||
# This VM uses a non-standard interface
|
||||
nomad_network_interface: ens3
|
||||
|
||||
consul_instances:
|
||||
children:
|
||||
servers: {}
|
||||
vault_instances:
|
||||
children:
|
||||
servers: {}
|
||||
nomad_instances:
|
||||
children:
|
||||
servers: {}
|
||||
nomad_instances:
|
||||
vars:
|
||||
nomad_network_interface: eth0
|
||||
children:
|
||||
nomad_servers: {}
|
||||
nomad_clients: {}
|
||||
nomad_servers:
|
||||
hosts:
|
||||
nonopi.thefij:
|
||||
ansible_host: 192.168.2.170
|
||||
n1.thefij: {}
|
||||
# n2.thefij: {}
|
||||
pi4: {}
|
||||
# qnomad.thefij: {}
|
||||
nomad_clients:
|
||||
hosts:
|
||||
n1.thefij: {}
|
||||
# n2.thefij: {}
|
||||
pi4: {}
|
||||
# qnomad.thefij: {}
|
||||
|
@ -1,80 +0,0 @@
|
||||
---
|
||||
- name: Bootstrap Consul values
|
||||
hosts: consul_instances
|
||||
gather_facts: false
|
||||
|
||||
vars_files:
|
||||
- vars/consul_values.yml
|
||||
|
||||
tasks:
|
||||
- name: Add values
|
||||
delegate_to: localhost
|
||||
run_once: true
|
||||
block:
|
||||
- name: Install python-consul
|
||||
pip:
|
||||
name: python-consul
|
||||
extra_args: --index-url https://pypi.org/simple
|
||||
|
||||
- name: Write values
|
||||
consul_kv:
|
||||
host: "{{ inventory_hostname }}"
|
||||
key: "{{ item.key }}"
|
||||
value: "{{ item.value }}"
|
||||
loop: "{{ consul_values | default({}) | dict2items }}"
|
||||
|
||||
- name: Bootstrap value values
|
||||
hosts: vault_instances
|
||||
gather_facts: false
|
||||
|
||||
vars_files:
|
||||
- vars/vault_hashi_vault_values.yml
|
||||
|
||||
tasks:
|
||||
- name: Bootstrap Vault secrets
|
||||
delegate_to: localhost
|
||||
run_once: true
|
||||
block:
|
||||
- name: Install hvac
|
||||
pip:
|
||||
name: hvac
|
||||
extra_args: --index-url https://pypi.org/simple
|
||||
|
||||
- name: Check mount
|
||||
community.hashi_vault.vault_read:
|
||||
url: "http://{{ inventory_hostname }}:8200"
|
||||
token: "{{ root_token }}"
|
||||
path: "/sys/mounts/kv"
|
||||
ignore_errors: true
|
||||
register: check_mount
|
||||
|
||||
- name: Create kv mount
|
||||
community.hashi_vault.vault_write:
|
||||
url: "http://{{ inventory_hostname }}:8200"
|
||||
token: "{{ root_token }}"
|
||||
path: "/sys/mounts/kv"
|
||||
data:
|
||||
type: kv-v2
|
||||
when: check_mount is not succeeded
|
||||
|
||||
- name: Write values
|
||||
no_log: true
|
||||
community.hashi_vault.vault_write:
|
||||
url: "http://{{ inventory_hostname }}:8200"
|
||||
token: "{{ root_token }}"
|
||||
path: "kv/data/{{ item.key }}"
|
||||
data:
|
||||
data:
|
||||
"{{ item.value }}"
|
||||
loop: "{{ hashi_vault_values | default({}) | dict2items }}"
|
||||
retries: 2
|
||||
delay: 10
|
||||
|
||||
- name: Write userpass
|
||||
no_log: true
|
||||
community.hashi_vault.vault_write:
|
||||
url: "http://{{ inventory_hostname }}:8200"
|
||||
token: "{{ root_token }}"
|
||||
path: "auth/userpass/users/{{ item.name }}"
|
||||
data: '{"password": "{{ item.password }}", "policies": "{{ item.policies }}"}'
|
||||
loop: "{{ vault_userpass }}"
|
@ -1,27 +1,5 @@
|
||||
# Stops Consul, Vault, and Nomad and clears all data from their data dirs
|
||||
# Stops Nomad and clears all data from its ata dirs
|
||||
---
|
||||
- name: Delete Consul data
|
||||
hosts: consul_instances
|
||||
|
||||
tasks:
|
||||
- name: Stop consul
|
||||
systemd:
|
||||
name: consul
|
||||
state: stopped
|
||||
become: true
|
||||
|
||||
- name: Stop vault
|
||||
systemd:
|
||||
name: vault
|
||||
state: stopped
|
||||
become: true
|
||||
|
||||
- name: Remove data dir
|
||||
file:
|
||||
path: /opt/consul
|
||||
state: absent
|
||||
become: true
|
||||
|
||||
- name: Delete Nomad data
|
||||
hosts: nomad_instances
|
||||
|
||||
|
27
ansible_playbooks/nomad_wesher_restart.yml
Normal file
27
ansible_playbooks/nomad_wesher_restart.yml
Normal file
@ -0,0 +1,27 @@
|
||||
- name: Restart nomad and wesher
|
||||
hosts: nomad_instances
|
||||
|
||||
tasks:
|
||||
- name: Stop Nomad
|
||||
systemd:
|
||||
name: nomad
|
||||
state: stopped
|
||||
become: true
|
||||
|
||||
- name: Restart wesher
|
||||
systemd:
|
||||
name: wesher
|
||||
state: restarted
|
||||
become: true
|
||||
|
||||
- name: Start Docker
|
||||
systemd:
|
||||
name: docker
|
||||
state: started
|
||||
become: true
|
||||
|
||||
- name: Start Nomad
|
||||
systemd:
|
||||
name: nomad
|
||||
state: started
|
||||
become: true
|
@ -1,84 +0,0 @@
|
||||
---
|
||||
- name: Stop Nomad
|
||||
hosts: nomad_instances
|
||||
|
||||
tasks:
|
||||
- name: Stop Nomad
|
||||
systemd:
|
||||
name: nomad
|
||||
state: stopped
|
||||
become: true
|
||||
|
||||
- name: Stop Vault
|
||||
hosts: nomad_instances
|
||||
|
||||
tasks:
|
||||
- name: Stop Vault
|
||||
systemd:
|
||||
name: vault
|
||||
state: stopped
|
||||
become: true
|
||||
|
||||
- name: Recover Consul
|
||||
hosts: consul_instances
|
||||
|
||||
tasks:
|
||||
- name: Stop Consul
|
||||
systemd:
|
||||
name: consul
|
||||
state: stopped
|
||||
become: true
|
||||
|
||||
- name: Get node-id
|
||||
slurp:
|
||||
src: /opt/consul/node-id
|
||||
register: consul_node_id
|
||||
become: true
|
||||
|
||||
- name: Node Info
|
||||
debug:
|
||||
msg: |
|
||||
node_id: {{ consul_node_id.content }}
|
||||
address: {{ ansible_default_ipv4.address }}
|
||||
|
||||
- name: Save
|
||||
copy:
|
||||
dest: "/opt/consul/raft/peers.json"
|
||||
# I used to have reject('equalto', inventory_hostname) in the loop, but I'm not sure if I should
|
||||
content: |
|
||||
[
|
||||
{% for host in ansible_play_hosts -%}
|
||||
{
|
||||
"id": "{{ hostvars[host].consul_node_id.content }}",
|
||||
"address": "{{ hostvars[host].ansible_default_ipv4.address }}:8300",
|
||||
"non_voter": false
|
||||
}{% if not loop.last %},{% endif %}
|
||||
{% endfor -%}
|
||||
]
|
||||
become: true
|
||||
|
||||
- name: Restart Consul
|
||||
systemd:
|
||||
name: consul
|
||||
state: restarted
|
||||
become: true
|
||||
|
||||
- name: Start Vault
|
||||
hosts: nomad_instances
|
||||
|
||||
tasks:
|
||||
- name: Start Vault
|
||||
systemd:
|
||||
name: vault
|
||||
state: started
|
||||
become: true
|
||||
|
||||
- name: Start Nomad
|
||||
hosts: nomad_instances
|
||||
|
||||
tasks:
|
||||
- name: Start Nomad
|
||||
systemd:
|
||||
name: nomad
|
||||
state: started
|
||||
become: true
|
@ -1,6 +1,7 @@
|
||||
---
|
||||
- name: Recover Nomad
|
||||
hosts: nomad_instances
|
||||
hosts: nomad_servers
|
||||
any_errors_fatal: true
|
||||
|
||||
tasks:
|
||||
- name: Stop Nomad
|
||||
@ -9,6 +10,10 @@
|
||||
state: stopped
|
||||
become: true
|
||||
|
||||
- name: Remount all shares
|
||||
command: mount -a
|
||||
become: true
|
||||
|
||||
- name: Get node-id
|
||||
slurp:
|
||||
src: /var/nomad/server/node-id
|
||||
@ -18,7 +23,7 @@
|
||||
- name: Node Info
|
||||
debug:
|
||||
msg: |
|
||||
node_id: {{ nomad_node_id.content }}
|
||||
node_id: {{ nomad_node_id.content | b64decode }}
|
||||
address: {{ ansible_default_ipv4.address }}
|
||||
|
||||
- name: Save
|
||||
@ -29,7 +34,7 @@
|
||||
[
|
||||
{% for host in ansible_play_hosts -%}
|
||||
{
|
||||
"id": "{{ hostvars[host].nomad_node_id.content }}",
|
||||
"id": "{{ hostvars[host].nomad_node_id.content | b64decode }}",
|
||||
"address": "{{ hostvars[host].ansible_default_ipv4.address }}:4647",
|
||||
"non_voter": false
|
||||
}{% if not loop.last %},{% endif %}
|
||||
|
@ -1,150 +1,20 @@
|
||||
---
|
||||
- name: Build Consul cluster
|
||||
hosts: consul_instances
|
||||
any_errors_fatal: true
|
||||
|
||||
roles:
|
||||
- role: ansible-consul
|
||||
vars:
|
||||
consul_version: "1.13.3-1"
|
||||
consul_install_upgrade: true
|
||||
consul_install_from_repo: true
|
||||
consul_os_repo_prerequisites: []
|
||||
|
||||
consul_node_role: server
|
||||
consul_raft_protocol: 3
|
||||
consul_bootstrap_expect: true
|
||||
consul_bootstrap_expect_value: "{{ [(play_hosts | length), 3] | min }}"
|
||||
|
||||
consul_user: consul
|
||||
consul_manage_user: true
|
||||
consul_group: bin
|
||||
consul_manage_group: true
|
||||
|
||||
# consul_tls_enable: true
|
||||
consul_connect_enabled: true
|
||||
consul_ports_grpc: 8502
|
||||
consul_client_address: "0.0.0.0"
|
||||
|
||||
# Autopilot
|
||||
# consul_autopilot_enable: true
|
||||
# consul_autopilot_cleanup_dead_Servers: true
|
||||
|
||||
# Enable metrics
|
||||
consul_config_custom:
|
||||
telemetry:
|
||||
prometheus_retention_time: "2h"
|
||||
|
||||
# DNS forwarding
|
||||
consul_dnsmasq_enable: true
|
||||
consul_dnsmasq_servers:
|
||||
# TODO: use addresses of other nomad nodes?
|
||||
# Maybe this can be [] to get the values from dhcp
|
||||
- 1.1.1.1
|
||||
- 1.0.0.1
|
||||
consul_dnsmasq_bind_interfaces: true
|
||||
consul_dnsmasq_listen_addresses:
|
||||
# Listen only to loopback interface
|
||||
- 127.0.0.1
|
||||
|
||||
become: true
|
||||
- name: Update DNS for bootstrapping with non-Nomad host
|
||||
hosts: nomad_instances
|
||||
become: true
|
||||
gather_facts: false
|
||||
vars:
|
||||
non_nomad_dns: 192.168.2.170
|
||||
|
||||
tasks:
|
||||
- name: Start Consul
|
||||
systemd:
|
||||
state: started
|
||||
name: consul
|
||||
become: true
|
||||
|
||||
# If DNS is broken after dnsmasq, then need to set /etc/resolv.conf to something
|
||||
# pointing to 127.0.0.1 and possibly restart Docker and Nomad
|
||||
# Actually, we should point to our external Nomad address so that Docker uses it
|
||||
- name: Update resolv.conf
|
||||
- name: Add non-nomad bootstrap DNS
|
||||
lineinfile:
|
||||
dest: /etc/resolv.conf
|
||||
create: true
|
||||
line: "nameserver {{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
|
||||
become: true
|
||||
|
||||
- name: Setup Vault cluster
|
||||
hosts: vault_instances
|
||||
|
||||
roles:
|
||||
- name: ansible-vault
|
||||
vars:
|
||||
vault_version: 1.12.0-1
|
||||
vault_install_hashi_repo: true
|
||||
vault_harden_file_perms: true
|
||||
# Maybe this should be restricted
|
||||
vault_group: bin
|
||||
vault_bin_path: /usr/bin
|
||||
vault_address: 0.0.0.0
|
||||
|
||||
vault_backend: consul
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: Get Vault status
|
||||
uri:
|
||||
url: http://127.0.0.1:8200/v1/sys/health
|
||||
method: GET
|
||||
status_code: 200, 429, 472, 473, 501, 503
|
||||
body_format: json
|
||||
return_content: true
|
||||
register: vault_status
|
||||
|
||||
- name: Initialize Vault
|
||||
when: not vault_status.json["initialized"]
|
||||
block:
|
||||
- name: Initialize Vault
|
||||
command:
|
||||
argv:
|
||||
- "vault"
|
||||
- "operator"
|
||||
- "init"
|
||||
- "-format=json"
|
||||
- "-address=http://127.0.0.1:8200/"
|
||||
- "-key-shares={{ vault_init_key_shares|default(3) }}"
|
||||
- "-key-threshold={{ vault_init_key_threshold|default(2) }}"
|
||||
run_once: true
|
||||
register: vault_init
|
||||
|
||||
- name: Save initialize result
|
||||
copy:
|
||||
content: "{{ vault_init.stdout }}"
|
||||
dest: "../vault-keys.json"
|
||||
when: vault_init is succeeded
|
||||
delegate_to: localhost
|
||||
run_once: true
|
||||
|
||||
- name: Unseal from init
|
||||
no_log: true
|
||||
command:
|
||||
argv:
|
||||
- "vault"
|
||||
- "operator"
|
||||
- "unseal"
|
||||
- "-address=http://127.0.0.1:8200/"
|
||||
- "{{ item }}"
|
||||
loop: "{{ (vault_init.stdout | from_json)['unseal_keys_hex'] }}"
|
||||
when: vault_init is succeeded
|
||||
|
||||
- name: Unseal Vault
|
||||
no_log: true
|
||||
command:
|
||||
argv:
|
||||
- "vault"
|
||||
- "operator"
|
||||
- "unseal"
|
||||
- "-address=http://127.0.0.1:8200/"
|
||||
- "{{ item }}"
|
||||
loop: "{{ unseal_keys_hex }}"
|
||||
when:
|
||||
- unseal_keys_hex is defined
|
||||
- vault_status.json["sealed"]
|
||||
line: "nameserver {{ non_nomad_dns }}"
|
||||
|
||||
- name: Install Docker
|
||||
hosts: nomad_instances
|
||||
hosts: nomad_clients
|
||||
become: true
|
||||
vars:
|
||||
docker_architecture_map:
|
||||
@ -174,8 +44,29 @@
|
||||
# state: present
|
||||
|
||||
- name: Create NFS mounts
|
||||
hosts: nomad_instances
|
||||
hosts: nomad_clients
|
||||
become: true
|
||||
vars:
|
||||
shared_nfs_mounts:
|
||||
- src: 192.168.2.10:/Media
|
||||
path: /srv/volumes/media-read
|
||||
opts: proto=tcp,port=2049,ro
|
||||
|
||||
- src: 192.168.2.10:/Media
|
||||
path: /srv/volumes/media-write
|
||||
opts: proto=tcp,port=2049,rw
|
||||
|
||||
- src: 192.168.2.10:/Overflow
|
||||
path: /srv/volumes/nas-overflow
|
||||
opts: proto=tcp,port=2049,rw
|
||||
|
||||
- src: 192.168.2.10:/Photos
|
||||
path: /srv/volumes/photos
|
||||
opts: proto=tcp,port=2049,rw
|
||||
|
||||
- src: 192.168.2.10:/Container
|
||||
path: /srv/volumes/nas-container
|
||||
opts: proto=tcp,port=2049,rw
|
||||
|
||||
tasks:
|
||||
- name: Install nfs
|
||||
@ -183,53 +74,16 @@
|
||||
name: nfs-common
|
||||
state: present
|
||||
|
||||
- name: Create Motioneye NFS mount
|
||||
- name: Mount NFS volumes
|
||||
ansible.posix.mount:
|
||||
src: 192.168.2.10:/Recordings/Motioneye
|
||||
path: /srv/volumes/motioneye-recordings
|
||||
opts: proto=tcp,port=2049,rw
|
||||
src: "{{ item.src }}"
|
||||
path: "{{ item.path }}"
|
||||
opts: "{{ item.opts }}"
|
||||
state: mounted
|
||||
fstype: nfs4
|
||||
loop: "{{ shared_nfs_mounts + (nfs_mounts | default([])) }}"
|
||||
|
||||
- name: Create Media Library RO NFS mount
|
||||
ansible.posix.mount:
|
||||
src: 192.168.2.10:/Multimedia
|
||||
path: /srv/volumes/media-read
|
||||
opts: proto=tcp,port=2049,ro
|
||||
state: mounted
|
||||
fstype: nfs4
|
||||
|
||||
- name: Create Media Library RW NFS mount
|
||||
ansible.posix.mount:
|
||||
src: 192.168.2.10:/Multimedia
|
||||
path: /srv/volumes/media-write
|
||||
opts: proto=tcp,port=2049,rw
|
||||
state: mounted
|
||||
fstype: nfs4
|
||||
|
||||
- name: Create Photo library NFS mount
|
||||
ansible.posix.mount:
|
||||
src: 192.168.2.10:/Photos
|
||||
path: /srv/volumes/photos
|
||||
opts: proto=tcp,port=2049,rw
|
||||
state: mounted
|
||||
fstype: nfs4
|
||||
|
||||
- name: Create Download RW NFS mount
|
||||
ansible.posix.mount:
|
||||
src: 192.168.2.10:/Download
|
||||
path: /srv/volumes/download
|
||||
opts: proto=tcp,port=2049,rw
|
||||
state: mounted
|
||||
fstype: nfs4
|
||||
|
||||
- name: Create Container NAS RW NFS mount
|
||||
ansible.posix.mount:
|
||||
src: 192.168.2.10:/Container
|
||||
path: /srv/volumes/container
|
||||
opts: proto=tcp,port=2049,rw
|
||||
state: mounted
|
||||
fstype: nfs4
|
||||
- import_playbook: wesher.yml
|
||||
|
||||
- name: Build Nomad cluster
|
||||
hosts: nomad_instances
|
||||
@ -238,12 +92,6 @@
|
||||
|
||||
vars:
|
||||
shared_host_volumes:
|
||||
- name: motioneye-recordings
|
||||
path: /srv/volumes/motioneye-recordings
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
- name: media-read
|
||||
path: /srv/volumes/media-write
|
||||
read_only: true
|
||||
@ -253,27 +101,45 @@
|
||||
group: "root"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
- name: tv-sonarr
|
||||
path: "/srv/volumes/media-write/TV Shows"
|
||||
owner: 1001
|
||||
group: 100
|
||||
- name: media-overflow-write
|
||||
path: /srv/volumes/nas-overflow/Media
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0755"
|
||||
read_only: false
|
||||
- name: download
|
||||
path: /srv/volumes/download
|
||||
owner: 1001
|
||||
group: 100
|
||||
mode: "0755"
|
||||
- name: media-downloads
|
||||
path: /srv/volumes/media-write/Downloads
|
||||
read_only: false
|
||||
- name: nzbget-data
|
||||
path: /srv/volumes/container/nzbget/config
|
||||
read_only: false
|
||||
- name: gitea-data
|
||||
path: /srv/volumes/container/gitea
|
||||
- name: sabnzbd-config
|
||||
path: /srv/volumes/media-write/Downloads/sabnzbd
|
||||
read_only: false
|
||||
- name: photoprism-media
|
||||
path: /srv/volumes/photos/Photoprism
|
||||
read_only: false
|
||||
- name: photoprism-storage
|
||||
path: /srv/volumes/nas-container/photoprism
|
||||
read_only: false
|
||||
- name: nzbget-config
|
||||
path: /srv/volumes/nas-container/nzbget
|
||||
read_only: false
|
||||
- name: sonarr-config
|
||||
path: /srv/volumes/nas-container/sonarr
|
||||
read_only: false
|
||||
- name: lidarr-config
|
||||
path: /srv/volumes/nas-container/lidarr
|
||||
read_only: false
|
||||
- name: radarr-config
|
||||
path: /srv/volumes/nas-container/radarr
|
||||
read_only: false
|
||||
- name: bazarr-config
|
||||
path: /srv/volumes/nas-container/bazarr
|
||||
read_only: false
|
||||
- name: gitea-data
|
||||
path: /srv/volumes/nas-container/gitea
|
||||
read_only: false
|
||||
- name: ytdl-web
|
||||
path: /srv/volumes/nas-container/ytdl-web
|
||||
read_only: false
|
||||
- name: all-volumes
|
||||
path: /srv/volumes
|
||||
owner: "root"
|
||||
@ -284,9 +150,10 @@
|
||||
roles:
|
||||
- name: ansible-nomad
|
||||
vars:
|
||||
nomad_version: "1.4.2-1"
|
||||
nomad_version: "1.8.4-1"
|
||||
nomad_install_upgrade: true
|
||||
nomad_allow_purge_config: true
|
||||
nomad_node_role: "{% if 'nomad_clients' in group_names %}{% if 'nomad_servers' in group_names %}both{% else %}client{% endif %}{% else %}server{% endif %}"
|
||||
|
||||
# Where nomad gets installed to
|
||||
nomad_bin_dir: /usr/bin
|
||||
@ -319,12 +186,14 @@
|
||||
docker:
|
||||
config:
|
||||
allow_privileged: true
|
||||
gc:
|
||||
image_delay: "24h"
|
||||
volumes:
|
||||
enabled: true
|
||||
selinuxlabel: "z"
|
||||
# Send logs to journald so we can scrape them for Loki
|
||||
logging:
|
||||
type: journald
|
||||
# logging:
|
||||
# type: journald
|
||||
extra_labels:
|
||||
- "job_name"
|
||||
- "job_id"
|
||||
@ -338,52 +207,27 @@
|
||||
nomad_bind_address: 0.0.0.0
|
||||
|
||||
# Default interface for binding tasks
|
||||
# nomad_network_interface: lo
|
||||
# This is now set at the inventory level
|
||||
# nomad_network_interface: eth0
|
||||
|
||||
# Create networks for binding task ports
|
||||
nomad_host_networks:
|
||||
- name: nomad-bridge
|
||||
interface: nomad
|
||||
reserved_ports: "22"
|
||||
- name: loopback
|
||||
interface: lo
|
||||
reserved_ports: "22"
|
||||
- name: wesher
|
||||
interface: wgoverlay
|
||||
reserved_ports: "22"
|
||||
|
||||
# Enable ACLs
|
||||
nomad_acl_enabled: true
|
||||
|
||||
# Enable vault integration
|
||||
# HACK: Only talk to local Vault for now because it doesn't have HTTPS
|
||||
# TODO: Would be really great to have this over https and point to vault.consul.service
|
||||
# nomad_vault_address: "https://vault.service.consul:8200"
|
||||
# Right now, each node only talks to it's local Vault, so if that node is rebooted and
|
||||
# that vault is sealed, it will not have access to vault. This is a problem if a node
|
||||
# must reboot.
|
||||
nomad_vault_address: "http://127.0.0.1:8200"
|
||||
# TODO: This fails on first run because the Nomad-Vault integration can't be set up
|
||||
# until Nomad has started. Could maybe figure out if ACLs have been set up and leave
|
||||
# these out until the later play, maybe just bootstrap the nomad-cluster role in Vault
|
||||
# befor Nomad is set up
|
||||
nomad_vault_create_from_role: "nomad-cluster"
|
||||
# TODO: (security) Probably want to restict this to a narrower scoped token
|
||||
nomad_vault_enabled: "{{ root_token is defined }}"
|
||||
nomad_vault_token: "{{ root_token | default('') }}"
|
||||
|
||||
nomad_config_custom:
|
||||
ui:
|
||||
enabled: true
|
||||
consul:
|
||||
ui_url: "https://consul.thefij.rocks/ui"
|
||||
vault:
|
||||
ui_url: "https://vault.thefij.rocks/ui"
|
||||
consul:
|
||||
tags:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.consulcatalog.connect=true"
|
||||
- "traefik.http.routers.nomadclient.entrypoints=websecure"
|
||||
|
||||
- name: Bootstrap Nomad ACLs and scheduler
|
||||
hosts: nomad_instances
|
||||
hosts: nomad_servers
|
||||
|
||||
tasks:
|
||||
- name: Start Nomad
|
||||
@ -397,9 +241,9 @@
|
||||
method: GET
|
||||
status_code: 200
|
||||
register: nomad_check_result
|
||||
retries: 6
|
||||
retries: 8
|
||||
until: nomad_check_result is succeeded
|
||||
delay: 10
|
||||
delay: 15
|
||||
changed_when: false
|
||||
run_once: true
|
||||
|
||||
@ -413,6 +257,7 @@
|
||||
run_once: true
|
||||
ignore_errors: true
|
||||
register: bootstrap_result
|
||||
changed_when: bootstrap_result is succeeded
|
||||
|
||||
- name: Save bootstrap result
|
||||
copy:
|
||||
@ -435,20 +280,6 @@
|
||||
changed_when: false
|
||||
register: read_secretid
|
||||
|
||||
- name: Enable service scheduler preemption
|
||||
command:
|
||||
argv:
|
||||
- nomad
|
||||
- operator
|
||||
- scheduler
|
||||
- set-config
|
||||
- -preempt-system-scheduler=true
|
||||
- -preempt-service-scheduler=true
|
||||
environment:
|
||||
NOMAD_TOKEN: "{{ read_secretid.stdout }}"
|
||||
delegate_to: "{{ play_hosts[0] }}"
|
||||
run_once: true
|
||||
|
||||
- name: Look for policy
|
||||
command:
|
||||
argv:
|
||||
@ -458,16 +289,17 @@
|
||||
- list
|
||||
environment:
|
||||
NOMAD_TOKEN: "{{ read_secretid.stdout }}"
|
||||
run_once: true
|
||||
register: policies
|
||||
run_once: true
|
||||
changed_when: false
|
||||
|
||||
- name: Copy policy
|
||||
copy:
|
||||
src: ../acls/nomad-anon-policy.hcl
|
||||
dest: /tmp/anonymous.policy.hcl
|
||||
delegate_to: "{{ play_hosts[0] }}"
|
||||
register: anon_policy
|
||||
run_once: true
|
||||
register: anon_policy
|
||||
|
||||
- name: Create anon-policy
|
||||
command:
|
||||
@ -476,7 +308,7 @@
|
||||
- acl
|
||||
- policy
|
||||
- apply
|
||||
- -description="Anon read only"
|
||||
- -description=Anon read only
|
||||
- anonymous
|
||||
- /tmp/anonymous.policy.hcl
|
||||
environment:
|
||||
@ -485,18 +317,56 @@
|
||||
delegate_to: "{{ play_hosts[0] }}"
|
||||
run_once: true
|
||||
|
||||
- name: Set up Nomad backend and roles in Vault
|
||||
community.general.terraform:
|
||||
project_path: ../acls
|
||||
force_init: true
|
||||
variables:
|
||||
consul_address: "{{ play_hosts[0] }}:8500"
|
||||
vault_token: "{{ root_token }}"
|
||||
nomad_secret_id: "{{ read_secretid.stdout }}"
|
||||
delegate_to: localhost
|
||||
- name: Read scheduler config
|
||||
command:
|
||||
argv:
|
||||
- nomad
|
||||
- operator
|
||||
- scheduler
|
||||
- get-config
|
||||
- -json
|
||||
run_once: true
|
||||
notify:
|
||||
- Restart Nomad
|
||||
register: scheduler_config
|
||||
changed_when: false
|
||||
|
||||
- name: Enable service scheduler preemption
|
||||
command:
|
||||
argv:
|
||||
- nomad
|
||||
- operator
|
||||
- scheduler
|
||||
- set-config
|
||||
- -preempt-service-scheduler=true
|
||||
environment:
|
||||
NOMAD_TOKEN: "{{ read_secretid.stdout }}"
|
||||
run_once: true
|
||||
when: (scheduler_config.stdout | from_json)["SchedulerConfig"]["PreemptionConfig"]["ServiceSchedulerEnabled"] is false
|
||||
|
||||
- name: Enable system scheduler preemption
|
||||
command:
|
||||
argv:
|
||||
- nomad
|
||||
- operator
|
||||
- scheduler
|
||||
- set-config
|
||||
- -preempt-system-scheduler=true
|
||||
environment:
|
||||
NOMAD_TOKEN: "{{ read_secretid.stdout }}"
|
||||
run_once: true
|
||||
when: (scheduler_config.stdout | from_json)["SchedulerConfig"]["PreemptionConfig"]["SystemSchedulerEnabled"] is false
|
||||
|
||||
# - name: Set up Nomad backend and roles in Vault
|
||||
# community.general.terraform:
|
||||
# project_path: ../acls
|
||||
# force_init: true
|
||||
# variables:
|
||||
# consul_address: "{{ play_hosts[0] }}:8500"
|
||||
# vault_token: "{{ root_token }}"
|
||||
# nomad_secret_id: "{{ read_secretid.stdout }}"
|
||||
# delegate_to: localhost
|
||||
# run_once: true
|
||||
# notify:
|
||||
# - Restart Nomad
|
||||
|
||||
handlers:
|
||||
- name: Restart Nomad
|
||||
|
@ -8,23 +8,3 @@
|
||||
name: nomad
|
||||
state: stopped
|
||||
become: true
|
||||
|
||||
- name: Stop Vault
|
||||
hosts: nomad_instances
|
||||
|
||||
tasks:
|
||||
- name: Stop Vault
|
||||
systemd:
|
||||
name: vault
|
||||
state: stopped
|
||||
become: true
|
||||
|
||||
- name: Stop Consul
|
||||
hosts: consul_instances
|
||||
|
||||
tasks:
|
||||
- name: Stop Consul
|
||||
systemd:
|
||||
name: consul
|
||||
state: stopped
|
||||
become: true
|
||||
|
@ -1,27 +0,0 @@
|
||||
---
|
||||
- name: Unseal Vault
|
||||
hosts: vault_instances
|
||||
|
||||
tasks:
|
||||
- name: Get Vault status
|
||||
uri:
|
||||
url: http://127.0.0.1:8200/v1/sys/health
|
||||
method: GET
|
||||
status_code: 200, 429, 472, 473, 501, 503
|
||||
body_format: json
|
||||
return_content: true
|
||||
register: vault_status
|
||||
|
||||
- name: Unseal Vault
|
||||
no_log: true
|
||||
command:
|
||||
argv:
|
||||
- "vault"
|
||||
- "operator"
|
||||
- "unseal"
|
||||
- "-address=http://127.0.0.1:8200/"
|
||||
- "{{ item }}"
|
||||
loop: "{{ unseal_keys_hex }}"
|
||||
when:
|
||||
- unseal_keys_hex is defined
|
||||
- vault_status.json["sealed"]
|
@ -1,4 +0,0 @@
|
||||
consul_values:
|
||||
"blocky/whitelists/ads": |
|
||||
- |
|
||||
somedomain.com
|
160
ansible_playbooks/vars/nomad_vars.sample.yml
Normal file
160
ansible_playbooks/vars/nomad_vars.sample.yml
Normal file
@ -0,0 +1,160 @@
|
||||
nomad/jobs:
|
||||
base_hostname: VALUE
|
||||
db_user_ro: VALUE
|
||||
ldap_base_dn: VALUE
|
||||
notify_email: VALUE
|
||||
nomad/jobs/authelia:
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
email_sender: VALUE
|
||||
jwt_secret: VALUE
|
||||
oidc_clients: VALUE
|
||||
oidc_hmac_secret: VALUE
|
||||
oidc_issuer_certificate_chain: VALUE
|
||||
oidc_issuer_private_key: VALUE
|
||||
session_secret: VALUE
|
||||
storage_encryption_key: VALUE
|
||||
nomad/jobs/authelia/authelia/stunnel:
|
||||
redis_stunnel_psk: VALUE
|
||||
nomad/jobs/backup:
|
||||
backup_passphrase: VALUE
|
||||
nas_ftp_host: VALUE
|
||||
nas_ftp_pass: VALUE
|
||||
nas_ftp_user: VALUE
|
||||
nas_minio_access_key_id: VALUE
|
||||
nas_minio_secret_access_key: VALUE
|
||||
nomad/jobs/backup-oneoff-n1:
|
||||
backup_passphrase: VALUE
|
||||
nas_ftp_host: VALUE
|
||||
nas_ftp_pass: VALUE
|
||||
nas_ftp_user: VALUE
|
||||
nas_minio_access_key_id: VALUE
|
||||
nas_minio_secret_access_key: VALUE
|
||||
nomad/jobs/backup-oneoff-n2:
|
||||
backup_passphrase: VALUE
|
||||
nas_ftp_host: VALUE
|
||||
nas_ftp_pass: VALUE
|
||||
nas_ftp_user: VALUE
|
||||
nas_minio_access_key_id: VALUE
|
||||
nas_minio_secret_access_key: VALUE
|
||||
nomad/jobs/backup-oneoff-pi4:
|
||||
backup_passphrase: VALUE
|
||||
nas_ftp_host: VALUE
|
||||
nas_ftp_pass: VALUE
|
||||
nas_ftp_user: VALUE
|
||||
nas_minio_access_key_id: VALUE
|
||||
nas_minio_secret_access_key: VALUE
|
||||
nomad/jobs/bazarr:
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
nomad/jobs/blocky:
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
mappings: VALUE
|
||||
whitelists_ads: VALUE
|
||||
nomad/jobs/blocky/blocky/stunnel:
|
||||
redis_stunnel_psk: VALUE
|
||||
nomad/jobs/ddclient:
|
||||
domain: VALUE
|
||||
domain_ddclient: VALUE
|
||||
zone: VALUE
|
||||
nomad/jobs/diun:
|
||||
slack_hook_url: VALUE
|
||||
nomad/jobs/git:
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
oidc_secret: VALUE
|
||||
secret_key: VALUE
|
||||
smtp_sender: VALUE
|
||||
nomad/jobs/grafana:
|
||||
admin_pw: VALUE
|
||||
alert_email_addresses: VALUE
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_pass_ro: VALUE
|
||||
db_user: VALUE
|
||||
db_user_ro: VALUE
|
||||
minio_access_key: VALUE
|
||||
minio_secret_key: VALUE
|
||||
oidc_secret: VALUE
|
||||
slack_bot_token: VALUE
|
||||
slack_bot_url: VALUE
|
||||
slack_hook_url: VALUE
|
||||
smtp_password: VALUE
|
||||
smtp_user: VALUE
|
||||
nomad/jobs/immich:
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
nomad/jobs/lego:
|
||||
acme_email: VALUE
|
||||
domain_lego_dns: VALUE
|
||||
usersfile: VALUE
|
||||
nomad/jobs/lidarr:
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
nomad/jobs/lldap:
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
jwt_secret: VALUE
|
||||
key_seed: VALUE
|
||||
smtp_from: VALUE
|
||||
smtp_reply_to: VALUE
|
||||
nomad/jobs/minitor:
|
||||
mailgun_api_key: VALUE
|
||||
nomad/jobs/mysql-server:
|
||||
mysql_root_password: VALUE
|
||||
nomad/jobs/photoprism:
|
||||
admin_password: VALUE
|
||||
admin_user: VALUE
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
oidc_secret: VALUE
|
||||
nomad/jobs/postgres-server:
|
||||
superuser: VALUE
|
||||
superuser_pass: VALUE
|
||||
nomad/jobs/radarr:
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
nomad/jobs/redis-authelia:
|
||||
allowed_psks: VALUE
|
||||
nomad/jobs/redis-blocky:
|
||||
allowed_psks: VALUE
|
||||
nomad/jobs/rediscommander:
|
||||
redis_stunnel_psk: VALUE
|
||||
nomad/jobs/sonarr:
|
||||
db_name: VALUE
|
||||
db_pass: VALUE
|
||||
db_user: VALUE
|
||||
nomad/jobs/traefik:
|
||||
external: VALUE
|
||||
usersfile: VALUE
|
||||
nomad/jobs/unifi-traffic-route-ips:
|
||||
unifi_password: VALUE
|
||||
unifi_username: VALUE
|
||||
nomad/oidc:
|
||||
secret: VALUE
|
||||
secrets/ldap:
|
||||
admin_email: VALUE
|
||||
admin_password: VALUE
|
||||
admin_user: VALUE
|
||||
secrets/mysql:
|
||||
mysql_root_password: VALUE
|
||||
secrets/postgres:
|
||||
superuser: VALUE
|
||||
superuser_pass: VALUE
|
||||
secrets/smtp:
|
||||
password: VALUE
|
||||
port: VALUE
|
||||
server: VALUE
|
||||
tls: VALUE
|
||||
user: VALUE
|
||||
|
@ -1,23 +0,0 @@
|
||||
# Example map of vault values to bootstrap
|
||||
# These should be encrypted with Ansible Vault if actually stored here
|
||||
hashi_vault_values:
|
||||
nextcloud:
|
||||
db_name: nextcloud
|
||||
# Eventually replace this with dynamic secrets from Hashicorp Vault
|
||||
db_user: nextcloud
|
||||
db_pass: nextcloud
|
||||
mysql:
|
||||
root_password: supersecretpassword
|
||||
slack:
|
||||
bot_url: ...
|
||||
bot_token: ...
|
||||
hook_url: ...
|
||||
grafana:
|
||||
alert_email_addresses: email@example.com
|
||||
backups:
|
||||
backup_passphrase: tellnoone
|
||||
|
||||
vault_userpass:
|
||||
- name: admin
|
||||
password: foo
|
||||
policies: default
|
2
ansible_playbooks/vars/wesher_vars.yml
Normal file
2
ansible_playbooks/vars/wesher_vars.yml
Normal file
@ -0,0 +1,2 @@
|
||||
---
|
||||
wesher_key: "{{ vault_wesher_key }}"
|
53
ansible_playbooks/wesher.yml
Normal file
53
ansible_playbooks/wesher.yml
Normal file
@ -0,0 +1,53 @@
|
||||
- name: Create overlay network
|
||||
hosts: nomad_instances
|
||||
become: true
|
||||
vars_files:
|
||||
- vars/wesher_vars.yml
|
||||
- vars/vault_wesher_vars.yml
|
||||
vars:
|
||||
wesher_key: "{{ wesher_key }}"
|
||||
wesher_version: v0.2.6
|
||||
wesher_arch_map:
|
||||
x86_64: amd64
|
||||
armv7l: arm
|
||||
aarch64: arm64
|
||||
wesher_arch: "{{ wesher_arch_map[ansible_architecture] }}"
|
||||
# wesher_sha256_map:
|
||||
# x86_64: 8c551ca211d7809246444765b5552a8d1742420c64eff5677d1e27a34c72aeef
|
||||
# armv7l: 97f5bbf2b00b8b11a4ca224540bf9c1affdb15432c3b6ad8da4c1a7b6175eb5d
|
||||
# aarch64: 507c6397d67ea90bddb3e1c06ec9d8e38d4342ed6f0f6b47855fecc9f1d6fae0
|
||||
# wesher_checksum: sha256:{{ wesher_sha256_map[ansible_architecture] }}
|
||||
wesher_checksum: sha256:https://github.com/costela/wesher/releases/download/{{ wesher_version }}/wesher.sha256sums
|
||||
|
||||
tasks:
|
||||
- name: Download wesher
|
||||
get_url:
|
||||
url: https://github.com/costela/wesher/releases/download/{{ wesher_version }}/wesher-{{ wesher_arch }}
|
||||
dest: /usr/local/sbin/wesher
|
||||
checksum: "{{ wesher_checksum }}"
|
||||
owner: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Install systemd unit
|
||||
get_url:
|
||||
url: https://github.com/costela/wesher/raw/{{ wesher_version }}/dist/wesher.service
|
||||
dest: /etc/systemd/system/wesher.service
|
||||
|
||||
- name: Write wesher config
|
||||
lineinfile:
|
||||
path: /etc/default/wesher
|
||||
create: true
|
||||
regexp: "^{{ item.split('=')[0] }}"
|
||||
line: "{{ item }}"
|
||||
owner: root
|
||||
mode: "0600"
|
||||
loop:
|
||||
- WESHER_CLUSTER_KEY={{ wesher_key }}
|
||||
- WESHER_JOIN={% for host in ansible_play_hosts %}{{ hostvars[host].ansible_default_ipv4.address }}{% if not loop.last %},{% endif %}{% endfor %}
|
||||
|
||||
- name: Start wesher
|
||||
systemd:
|
||||
name: wesher.service
|
||||
daemon_reload: true
|
||||
state: started
|
||||
enabled: true
|
40
backups/.terraform.lock.hcl
Normal file
40
backups/.terraform.lock.hcl
Normal file
@ -0,0 +1,40 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "2.0.0"
|
||||
hashes = [
|
||||
"h1:lIHIxA6ZmfyTGL3J9YIddhxlfit4ipSS09BLxkwo6L0=",
|
||||
"zh:09b897d64db293f9a904a4a0849b11ec1e3fff5c638f734d82ae36d8dc044b72",
|
||||
"zh:435cc106799290f64078ec24b6c59cb32b33784d609088638ed32c6d12121199",
|
||||
"zh:7073444bd064e8c4ec115ca7d9d7f030cc56795c0a83c27f6668bba519e6849a",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:79d238c35d650d2d83a439716182da63f3b2767e72e4cbd0b69cb13d9b1aebfc",
|
||||
"zh:7ef5f49344278fe0bbc5447424e6aa5425ff1821d010d944a444d7fa2c751acf",
|
||||
"zh:92179091638c8ba03feef371c4361a790190f9955caea1fa59de2055c701a251",
|
||||
"zh:a8a34398851761368eb8e7c171f24e55efa6e9fdbb5c455f6dec34dc17f631bc",
|
||||
"zh:b38fd5338625ebace5a4a94cea1a28b11bd91995d834e318f47587cfaf6ec599",
|
||||
"zh:b71b273a2aca7ad5f1e07c767b25b5a888881ba9ca93b30044ccc39c2937f03c",
|
||||
"zh:cd14357e520e0f09fb25badfb4f2ee37d7741afdc3ed47c7bcf54c1683772543",
|
||||
"zh:e05e025f4bb95138c3c8a75c636e97cd7cfd2fc1525b0c8bd097db8c5f02df6e",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.5.1"
|
||||
hashes = [
|
||||
"h1:VSnd9ZIPyfKHOObuQCaKfnjIHRtR7qTw19Rz8tJxm+k=",
|
||||
"zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64",
|
||||
"zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d",
|
||||
"zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831",
|
||||
"zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3",
|
||||
"zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b",
|
||||
"zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2",
|
||||
"zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865",
|
||||
"zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03",
|
||||
"zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602",
|
||||
"zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014",
|
||||
]
|
||||
}
|
242
backups/backup.nomad
Normal file
242
backups/backup.nomad
Normal file
@ -0,0 +1,242 @@
|
||||
job "backup%{ if batch_node != null }-oneoff-${batch_node}%{ endif }" {
|
||||
datacenters = ["dc1"]
|
||||
priority = 90
|
||||
%{ if batch_node == null ~}
|
||||
type = "system"
|
||||
%{ else ~}
|
||||
type = "batch"
|
||||
|
||||
parameterized {
|
||||
meta_required = ["job_name"]
|
||||
meta_optional = ["task", "snapshot"]
|
||||
|
||||
}
|
||||
|
||||
meta {
|
||||
task = "backup"
|
||||
snapshot = "latest"
|
||||
}
|
||||
%{ endif ~}
|
||||
|
||||
%{ if batch_node != null ~}
|
||||
constraint {
|
||||
attribute = "$${node.unique.name}"
|
||||
value = "${batch_node}"
|
||||
}
|
||||
%{ endif ~}
|
||||
|
||||
group "backup" {
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
|
||||
port "metrics" {
|
||||
%{~ if use_wesher ~}
|
||||
host_network = "wesher"
|
||||
%{~ endif ~}
|
||||
to = 8080
|
||||
}
|
||||
}
|
||||
|
||||
volume "all-volumes" {
|
||||
type = "host"
|
||||
read_only = false
|
||||
source = "all-volumes"
|
||||
}
|
||||
|
||||
ephemeral_disk {
|
||||
# Try to keep restic cache intact
|
||||
sticky = true
|
||||
}
|
||||
|
||||
service {
|
||||
name = "backup"
|
||||
provider = "nomad"
|
||||
port = "metrics"
|
||||
|
||||
tags = [
|
||||
"prometheus.scrape"
|
||||
]
|
||||
}
|
||||
|
||||
task "backup" {
|
||||
driver = "docker"
|
||||
|
||||
shutdown_delay = "5m"
|
||||
|
||||
volume_mount {
|
||||
volume = "all-volumes"
|
||||
destination = "/data"
|
||||
read_only = false
|
||||
}
|
||||
|
||||
config {
|
||||
image = "iamthefij/resticscheduler:0.4.0"
|
||||
ports = ["metrics"]
|
||||
args = [
|
||||
%{ if batch_node != null ~}
|
||||
"-once",
|
||||
"-$${NOMAD_META_task}",
|
||||
"$${NOMAD_META_job_name}",
|
||||
"--snapshot",
|
||||
"$${NOMAD_META_snapshot}",
|
||||
"--push-gateway",
|
||||
"http://pushgateway.nomad:9091",
|
||||
%{ endif ~}
|
||||
"$${NOMAD_TASK_DIR}/node-jobs.hcl",
|
||||
]
|
||||
}
|
||||
|
||||
action "unlockenv" {
|
||||
command = "sh"
|
||||
args = ["-c", "/bin/resticscheduler -once -unlock all $${NOMAD_TASK_DIR}/node-jobs.hcl"]
|
||||
}
|
||||
|
||||
action "unlocktmpl" {
|
||||
command = "/bin/resticscheduler"
|
||||
args = ["-once", "-unlock", "all", "{{ env 'NOMAD_TASK_DIR' }}/node-jobs.hcl"]
|
||||
}
|
||||
|
||||
action "unlockhc" {
|
||||
command = "/bin/resticscheduler"
|
||||
args = ["-once", "-unlock", "all", "/local/node-jobs.hcl"]
|
||||
}
|
||||
|
||||
env = {
|
||||
RCLONE_CHECKERS = "2"
|
||||
RCLONE_TRANSFERS = "2"
|
||||
RCLONE_FTP_CONCURRENCY = "5"
|
||||
RESTIC_CACHE_DIR = "$${NOMAD_ALLOC_DIR}/data"
|
||||
TZ = "America/Los_Angeles"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
MYSQL_HOST=127.0.0.1
|
||||
MYSQL_PORT=3306
|
||||
{{ with nomadVar "secrets/mysql" }}
|
||||
MYSQL_USER=root
|
||||
MYSQL_PASSWORD={{ .mysql_root_password }}
|
||||
{{ end -}}
|
||||
{{ with nomadVar "secrets/postgres" }}
|
||||
POSTGRES_HOST=127.0.0.1
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER={{ .superuser }}
|
||||
POSTGRES_PASSWORD={{ .superuser_password }}
|
||||
{{ end -}}
|
||||
{{ with nomadVar (print "nomad/jobs/" (index (env "NOMAD_JOB_ID" | split "/") 0)) -}}
|
||||
BACKUP_PASSPHRASE={{ .backup_passphrase }}
|
||||
RCLONE_FTP_HOST={{ .nas_ftp_host }}
|
||||
RCLONE_FTP_USER={{ .nas_ftp_user }}
|
||||
RCLONE_FTP_PASS={{ .nas_ftp_pass.Value | toJSON }}
|
||||
RCLONE_FTP_EXPLICIT_TLS=true
|
||||
RCLONE_FTP_NO_CHECK_CERTIFICATE=true
|
||||
AWS_ACCESS_KEY_ID={{ .nas_minio_access_key_id }}
|
||||
AWS_SECRET_ACCESS_KEY={{ .nas_minio_secret_access_key }}
|
||||
{{ end -}}
|
||||
EOF
|
||||
destination = "secrets/db.env"
|
||||
env = true
|
||||
}
|
||||
|
||||
template {
|
||||
# Build jobs based on node
|
||||
data = <<EOF
|
||||
# Current node is {{ env "node.unique.name" }} {{ env "node.unique.id" }}
|
||||
|
||||
%{ for job_file in fileset(module_path, "jobs/*.hcl") ~}
|
||||
{{ range nomadService 1 "backups" "${trimsuffix(basename(job_file), ".hcl")}" -}}
|
||||
# ${trimsuffix(basename(job_file), ".hcl")} .Node {{ .Node }}
|
||||
{{ if eq .Node (env "node.unique.id") -}}
|
||||
${file("${module_path}/${job_file}")}
|
||||
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
%{ endfor ~}
|
||||
|
||||
# Dummy job to keep task healthy on node without any stateful services
|
||||
job "Dummy" {
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "/local/dummy-repo"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = ["/local/node-jobs.hcl"]
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 1
|
||||
}
|
||||
}
|
||||
EOF
|
||||
destination = "local/node-jobs.hcl"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 500
|
||||
}
|
||||
}
|
||||
|
||||
task "stunnel" {
|
||||
driver = "docker"
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = true
|
||||
}
|
||||
|
||||
config {
|
||||
image = "iamthefij/stunnel:1.0.0"
|
||||
args = ["$${NOMAD_TASK_DIR}/stunnel.conf"]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 100
|
||||
memory = 100
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
syslog = no
|
||||
foreground = yes
|
||||
delay = yes
|
||||
|
||||
[mysql_client]
|
||||
client = yes
|
||||
accept = 127.0.0.1:3306
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "mysql-tls" }}
|
||||
connect = {{ .Address }}:{{ .Port }}
|
||||
{{ end }}
|
||||
PSKsecrets = {{ env "NOMAD_SECRETS_DIR" }}/mysql_stunnel_psk.txt
|
||||
|
||||
[postgres_client]
|
||||
client = yes
|
||||
accept = 127.0.0.1:5432
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "postgres-tls" }}
|
||||
connect = {{ .Address }}:{{ .Port }}
|
||||
{{ end }}
|
||||
PSKsecrets = {{ env "NOMAD_SECRETS_DIR" }}/postgres_stunnel_psk.txt
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/stunnel.conf"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{- with nomadVar "secrets/mysql/allowed_psks/backups" }}{{ .psk }}{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/mysql_stunnel_psk.txt"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{- with nomadVar "secrets/postgres/allowed_psks/backups" }}{{ .psk }}{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/postgres_stunnel_psk.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
136
backups/backups.tf
Normal file
136
backups/backups.tf
Normal file
@ -0,0 +1,136 @@
|
||||
resource "nomad_job" "backup" {
|
||||
jobspec = templatefile("${path.module}/backup.nomad", {
|
||||
module_path = path.module,
|
||||
batch_node = null,
|
||||
use_wesher = var.use_wesher
|
||||
})
|
||||
}
|
||||
|
||||
resource "nomad_job" "backup-oneoff" {
|
||||
# TODO: Get list of nomad hosts dynamically
|
||||
for_each = toset(["n1", "pi4"])
|
||||
# for_each = toset([
|
||||
# for node in data.consul_service.nomad.service :
|
||||
# node.node_name
|
||||
# ])
|
||||
|
||||
jobspec = templatefile("${path.module}/backup.nomad", {
|
||||
module_path = path.module,
|
||||
batch_node = each.key,
|
||||
use_wesher = var.use_wesher
|
||||
})
|
||||
}
|
||||
|
||||
locals {
|
||||
# NOTE: This can't be dynamic in first deploy since these values are not known
|
||||
# all_job_ids = toset(flatten([[for job in resource.nomad_job.backup-oneoff : job.id], [resource.nomad_job.backup.id]]))
|
||||
all_job_ids = toset(["backup", "backup-oneoff-n1", "backup-oneoff-pi4"])
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "secrets_mysql" {
|
||||
for_each = local.all_job_ids
|
||||
|
||||
name = "${each.key}-secrets-mysql"
|
||||
description = "Give access to MySQL secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/mysql" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = each.key
|
||||
}
|
||||
}
|
||||
|
||||
resource "random_password" "mysql_psk" {
|
||||
length = 32
|
||||
override_special = "!@#%&*-_="
|
||||
}
|
||||
|
||||
resource "nomad_variable" "mysql_psk" {
|
||||
path = "secrets/mysql/allowed_psks/backups"
|
||||
items = {
|
||||
psk = "backups:${resource.random_password.mysql_psk.result}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "mysql_psk" {
|
||||
for_each = local.all_job_ids
|
||||
|
||||
name = "${each.key}-secrets-mysql-psk"
|
||||
description = "Give access to MySQL PSK secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/mysql/allowed_psks/backups" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = each.key
|
||||
group = "backup"
|
||||
task = "stunnel"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "secrets_postgres" {
|
||||
for_each = local.all_job_ids
|
||||
|
||||
name = "${each.key}-secrets-postgres"
|
||||
description = "Give access to Postgres secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/postgres" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = each.key
|
||||
}
|
||||
}
|
||||
|
||||
resource "random_password" "postgres_psk" {
|
||||
length = 32
|
||||
override_special = "!@#%&*-_="
|
||||
}
|
||||
|
||||
resource "nomad_variable" "postgres_psk" {
|
||||
path = "secrets/postgres/allowed_psks/backups"
|
||||
items = {
|
||||
psk = "backups:${resource.random_password.postgres_psk.result}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "postgres_psk" {
|
||||
for_each = local.all_job_ids
|
||||
|
||||
name = "${each.key}-secrets-postgres-psk"
|
||||
description = "Give access to Postgres PSK secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/postgres/allowed_psks/backups" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = each.key
|
||||
group = "backup"
|
||||
task = "stunnel"
|
||||
}
|
||||
}
|
54
backups/jobs/authelia.hcl
Normal file
54
backups/jobs/authelia.hcl
Normal file
@ -0,0 +1,54 @@
|
||||
job "authelia" {
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/authelia"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
task "Create local authelia dir" {
|
||||
pre_script {
|
||||
on_backup = "mkdir -p /local/authelia"
|
||||
}
|
||||
}
|
||||
|
||||
task "Backup database" {
|
||||
mysql "Backup database" {
|
||||
hostname = env("MYSQL_HOST")
|
||||
port = env("MYSQL_PORT")
|
||||
database = "authelia"
|
||||
username = env("MYSQL_USER")
|
||||
password = env("MYSQL_PASSWORD")
|
||||
no_tablespaces = true
|
||||
dump_to = "/local/authelia/dump.sql"
|
||||
}
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = ["/local/authelia"]
|
||||
|
||||
backup_opts {
|
||||
Host = "nomad"
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepHourly = 24
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
57
backups/jobs/git.hcl
Normal file
57
backups/jobs/git.hcl
Normal file
@ -0,0 +1,57 @@
|
||||
job "git" {
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/gitea"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
task "Create local gitea dir" {
|
||||
pre_script {
|
||||
on_backup = "mkdir -p /local/gitea"
|
||||
}
|
||||
}
|
||||
|
||||
task "Backup database" {
|
||||
mysql "Backup database" {
|
||||
hostname = env("MYSQL_HOST")
|
||||
port = env("MYSQL_PORT")
|
||||
database = "gitea"
|
||||
username = env("MYSQL_USER")
|
||||
password = env("MYSQL_PASSWORD")
|
||||
no_tablespaces = true
|
||||
dump_to = "/local/gitea/dump.sql"
|
||||
}
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = [
|
||||
"/local/gitea",
|
||||
"/data/nas-container/gitea",
|
||||
]
|
||||
|
||||
backup_opts {
|
||||
Host = "nomad"
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepHourly = 24
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
job "grafana" {
|
||||
schedule = "0 * * * *"
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "rclone::ftp,env_auth:/nomad/grafana"
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/grafana"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
task "Create local grafana dir" {
|
||||
@ -26,14 +30,25 @@ job "grafana" {
|
||||
|
||||
backup {
|
||||
paths = ["/local/grafana"]
|
||||
# Because path is absolute
|
||||
|
||||
backup_opts {
|
||||
Host = "nomad"
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepHourly = 24
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
64
backups/jobs/lidarr.hcl
Normal file
64
backups/jobs/lidarr.hcl
Normal file
@ -0,0 +1,64 @@
|
||||
job "lidarr" {
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/lidarr"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
task "Backup main database" {
|
||||
postgres "Backup database" {
|
||||
hostname = env("POSTGRES_HOST")
|
||||
port = env("POSTGRES_PORT")
|
||||
username = env("POSTGRES_USER")
|
||||
password = env("POSTGRES_PASSWORD")
|
||||
database = "lidarr"
|
||||
no_tablespaces = true
|
||||
dump_to = "/data/nas-container/lidarr/Backups/dump-lidarr.sql"
|
||||
}
|
||||
}
|
||||
|
||||
task "Backup logs database" {
|
||||
postgres "Backup database" {
|
||||
hostname = env("POSTGRES_HOST")
|
||||
port = env("POSTGRES_PORT")
|
||||
username = env("POSTGRES_USER")
|
||||
password = env("POSTGRES_PASSWORD")
|
||||
database = "lidarr-logs"
|
||||
no_tablespaces = true
|
||||
dump_to = "/data/nas-container/lidarr/Backups/dump-lidarr-logs.sql"
|
||||
}
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = ["/data/nas-container/lidarr"]
|
||||
|
||||
backup_opts {
|
||||
Exclude = [
|
||||
"lidarr_backup_*.zip",
|
||||
"/data/nas-container/lidarr/MediaCover",
|
||||
"/data/nas-container/lidarr/logs",
|
||||
]
|
||||
Host = "nomad"
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
53
backups/jobs/lldap.hcl
Normal file
53
backups/jobs/lldap.hcl
Normal file
@ -0,0 +1,53 @@
|
||||
job "lldap" {
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/lldap"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
task "Create local backup dir" {
|
||||
pre_script {
|
||||
on_backup = "mkdir -p /local/lldap"
|
||||
}
|
||||
}
|
||||
|
||||
task "Backup database" {
|
||||
mysql "Backup database" {
|
||||
hostname = env("MYSQL_HOST")
|
||||
port = env("MYSQL_PORT")
|
||||
username = env("MYSQL_USER")
|
||||
password = env("MYSQL_PASSWORD")
|
||||
database = "lldap"
|
||||
no_tablespaces = true
|
||||
dump_to = "/local/lldap/dump.sql"
|
||||
}
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = ["/local/lldap"]
|
||||
|
||||
backup_opts {
|
||||
Host = "nomad"
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
41
backups/jobs/nzbget.hcl
Normal file
41
backups/jobs/nzbget.hcl
Normal file
@ -0,0 +1,41 @@
|
||||
job "nzbget" {
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/nzbget"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = [
|
||||
# Configuration
|
||||
"/data/nas-container/nzbget",
|
||||
# Queued nzb files
|
||||
"/data/media-write/Downloads/nzb",
|
||||
]
|
||||
|
||||
backup_opts {
|
||||
Host = "nomad"
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepHourly = 24
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
60
backups/jobs/photoprism.hcl
Normal file
60
backups/jobs/photoprism.hcl
Normal file
@ -0,0 +1,60 @@
|
||||
job "photoprism" {
|
||||
schedule = "10 * * * *"
|
||||
|
||||
config {
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/photoprism"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
task "Create local photoprism dir" {
|
||||
pre_script {
|
||||
on_backup = "mkdir -p /local/photoprism"
|
||||
}
|
||||
}
|
||||
|
||||
task "Dump database" {
|
||||
mysql "Dump database" {
|
||||
hostname = env("MYSQL_HOST")
|
||||
port = env("MYSQL_PORT")
|
||||
database = "photoprism"
|
||||
username = env("MYSQL_USER")
|
||||
password = env("MYSQL_PASSWORD")
|
||||
no_tablespaces = true
|
||||
dump_to = "/local/photoprism/dump.sql"
|
||||
}
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = [
|
||||
"/local/photoprism",
|
||||
"/data/nas-container/photoprism",
|
||||
]
|
||||
|
||||
backup_opts {
|
||||
Host = "nomad"
|
||||
Exclude = [
|
||||
"/data/nas-container/photoprism/cache",
|
||||
]
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepHourly = 24
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
64
backups/jobs/radarr.hcl
Normal file
64
backups/jobs/radarr.hcl
Normal file
@ -0,0 +1,64 @@
|
||||
job "radarr" {
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/radarr"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
task "Backup main database" {
|
||||
postgres "Backup database" {
|
||||
hostname = env("POSTGRES_HOST")
|
||||
port = env("POSTGRES_PORT")
|
||||
username = env("POSTGRES_USER")
|
||||
password = env("POSTGRES_PASSWORD")
|
||||
database = "radarr"
|
||||
no_tablespaces = true
|
||||
dump_to = "/data/nas-container/radarr/Backups/dump-radarr.sql"
|
||||
}
|
||||
}
|
||||
|
||||
task "Backup logs database" {
|
||||
postgres "Backup database" {
|
||||
hostname = env("POSTGRES_HOST")
|
||||
port = env("POSTGRES_PORT")
|
||||
username = env("POSTGRES_USER")
|
||||
password = env("POSTGRES_PASSWORD")
|
||||
database = "radarr-logs"
|
||||
no_tablespaces = true
|
||||
dump_to = "/data/nas-container/radarr/Backups/dump-radarr-logs.sql"
|
||||
}
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = ["/data/nas-container/radarr"]
|
||||
|
||||
backup_opts {
|
||||
Exclude = [
|
||||
"radarr_backup_*.zip",
|
||||
"/data/nas-container/radarr/MediaCover",
|
||||
"/data/nas-container/radarr/logs",
|
||||
]
|
||||
Host = "nomad"
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
36
backups/jobs/sabnzbd.hcl
Normal file
36
backups/jobs/sabnzbd.hcl
Normal file
@ -0,0 +1,36 @@
|
||||
job "sabnzbd" {
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/sabnzbd"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = ["/data/media-write/Downloads/sabnzbd"]
|
||||
|
||||
backup_opts {
|
||||
Host = "nomad"
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepHourly = 24
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
67
backups/jobs/sonarr.hcl
Normal file
67
backups/jobs/sonarr.hcl
Normal file
@ -0,0 +1,67 @@
|
||||
job "sonarr" {
|
||||
schedule = "@daily"
|
||||
|
||||
config {
|
||||
repo = "s3://backups-minio.agnosticfront.thefij:8443/nomad/sonarr"
|
||||
passphrase = env("BACKUP_PASSPHRASE")
|
||||
|
||||
options {
|
||||
InsecureTls = true
|
||||
}
|
||||
}
|
||||
|
||||
task "Backup main database" {
|
||||
postgres "Backup database" {
|
||||
hostname = env("POSTGRES_HOST")
|
||||
port = env("POSTGRES_PORT")
|
||||
username = env("POSTGRES_USER")
|
||||
password = env("POSTGRES_PASSWORD")
|
||||
database = "sonarr"
|
||||
no_tablespaces = true
|
||||
dump_to = "/data/nas-container/sonarr/Backups/dump-sonarr.sql"
|
||||
}
|
||||
}
|
||||
|
||||
task "Backup logs database" {
|
||||
postgres "Backup database" {
|
||||
hostname = env("POSTGRES_HOST")
|
||||
port = env("POSTGRES_PORT")
|
||||
username = env("POSTGRES_USER")
|
||||
password = env("POSTGRES_PASSWORD")
|
||||
database = "sonarr-logs"
|
||||
no_tablespaces = true
|
||||
dump_to = "/data/nas-container/sonarr/Backups/dump-sonarr-logs.sql"
|
||||
}
|
||||
}
|
||||
|
||||
backup {
|
||||
paths = ["/data/nas-container/sonarr"]
|
||||
|
||||
backup_opts {
|
||||
Exclude = [
|
||||
"sonarr_backup_*.zip",
|
||||
"/data/nas-container/sonarr/MediaCover",
|
||||
"/data/nas-container/sonarr/logs",
|
||||
"*.db",
|
||||
"*.db-shm",
|
||||
"*.db-wal",
|
||||
]
|
||||
Host = "nomad"
|
||||
}
|
||||
|
||||
restore_opts {
|
||||
Host = ["nomad"]
|
||||
# Because path is absolute
|
||||
Target = "/"
|
||||
}
|
||||
}
|
||||
|
||||
forget {
|
||||
KeepLast = 2
|
||||
KeepDaily = 30
|
||||
KeepWeekly = 8
|
||||
KeepMonthly = 6
|
||||
KeepYearly = 2
|
||||
Prune = true
|
||||
}
|
||||
}
|
5
backups/vars.tf
Normal file
5
backups/vars.tf
Normal file
@ -0,0 +1,5 @@
|
||||
variable "use_wesher" {
|
||||
type = bool
|
||||
description = "Indicates whether or not services should expose themselves on the wesher network"
|
||||
default = true
|
||||
}
|
12
core.tf
12
core.tf
@ -1,12 +0,0 @@
|
||||
module "databases" {
|
||||
source = "./databases"
|
||||
}
|
||||
|
||||
module "core" {
|
||||
source = "./core"
|
||||
|
||||
base_hostname = var.base_hostname
|
||||
|
||||
# Metrics and Blocky depend on databases
|
||||
depends_on = [module.databases]
|
||||
}
|
@ -1,59 +1,40 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/consul" {
|
||||
version = "2.16.2"
|
||||
hashes = [
|
||||
"h1:epldE7sZPBTQHnWEA4WlNJIOVT1UEX+/02SMg5nniaE=",
|
||||
"zh:0a2e11ca2ba650954951a087a1daec95eee2f3000456b295409a9880c4a10b1a",
|
||||
"zh:34f6bda06a0d1c213fa8d87d4313687681e67bc8c40c4cbaa7dbe59ce24a4f7e",
|
||||
"zh:5b85cf93db11ee890f720c317a38158927071feb634855786a0c0cd65825a43c",
|
||||
"zh:75ef915f3d087e6045751a66fbb7066a852a0944ec8c97200d1134dd84df7ffc",
|
||||
"zh:8a4a95697bd91ad51a581c12fe50ac61a114afba27895d027f77ac4154a7ea15",
|
||||
"zh:973d538c8d72793861a1ac9718249a9493f417a2b5096846367560054fd843b9",
|
||||
"zh:9feb2bdc06fdc2d8370cc9aad9a0c69e7e5ae38aac43f315c3f57507c57be030",
|
||||
"zh:c5709672d0afecbbe298bf519741ebcb9d04f02a73b5ee0c186dfa241aa5a524",
|
||||
"zh:c65c60570de6da7190e1e7762577655a463caeb59bc5d38e33034821ed0cbcb9",
|
||||
"zh:c958d6282650fc472aade61d5df4300936033f43cfb898293ef86aceccdfdf1d",
|
||||
"zh:cdd3632c81e1d11d3becd193aaa061688840f39147950c45c4301d042743ae6a",
|
||||
"zh:f3d3efac504c9484a025beb919d22b290aa6dbff256f6e86c1f8ce7817e077e5",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/external" {
|
||||
version = "2.2.2"
|
||||
hashes = [
|
||||
"h1:e7RpnZ2PbJEEPnfsg7V0FNwbfSk0/Z3FdrLsXINBmDY=",
|
||||
"zh:0b84ab0af2e28606e9c0c1289343949339221c3ab126616b831ddb5aaef5f5ca",
|
||||
"zh:10cf5c9b9524ca2e4302bf02368dc6aac29fb50aeaa6f7758cce9aa36ae87a28",
|
||||
"zh:56a016ee871c8501acb3f2ee3b51592ad7c3871a1757b098838349b17762ba6b",
|
||||
"zh:719d6ef39c50e4cffc67aa67d74d195adaf42afcf62beab132dafdb500347d39",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:7fbfc4d37435ac2f717b0316f872f558f608596b389b895fcb549f118462d327",
|
||||
"zh:8ac71408204db606ce63fe8f9aeaf1ddc7751d57d586ec421e62d440c402e955",
|
||||
"zh:a4cacdb06f114454b6ed0033add28006afa3f65a0ea7a43befe45fc82e6809fb",
|
||||
"zh:bb5ce3132b52ae32b6cc005bc9f7627b95259b9ffe556de4dad60d47d47f21f0",
|
||||
"zh:bb60d2976f125ffd232a7ccb4b3f81e7109578b23c9c6179f13a11d125dca82a",
|
||||
"zh:f9540ecd2e056d6e71b9ea5f5a5cf8f63dd5c25394b9db831083a9d4ea99b372",
|
||||
"zh:ffd998b55b8a64d4335a090b6956b4bf8855b290f7554dd38db3302de9c41809",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "1.4.19"
|
||||
version = "2.1.1"
|
||||
hashes = [
|
||||
"h1:EdBny2gaLr/IE+l+6csyCKeIGFMYZ/4tHKpcbS7ArgE=",
|
||||
"zh:2f3ceeb3318a6304026035b0ac9ee3e52df04913bb9ee78827e58c5398b41254",
|
||||
"zh:3fbe76c7d957d20dfe3c8c0528b33084651f22a95be9e0452b658e0922916e2a",
|
||||
"zh:595671a05828cfe6c42ef73aac894ac39f81a52cc662a76f37eb74ebe04ddf75",
|
||||
"zh:5d76e8788d2af3e60daf8076babf763ec887480bbb9734baccccd8fcddf4f03e",
|
||||
"zh:676985afeaca6e67b22d60d43fd0ed7055763029ffebc3026089fe2fd3b4a288",
|
||||
"zh:69152ce6164ac999a640cff962ece45208270e1ac37c10dac484eeea5cf47275",
|
||||
"zh:6da0b15c05b81f947ec8e139bd81eeeb05c0d36eb5a967b985d0625c60998b40",
|
||||
"h1:liQBgBXfQEYmwpoGZUfSsu0U0t/nhvuRZbMhaMz7wcQ=",
|
||||
"zh:28bc6922e8a21334568410760150d9d413d7b190d60b5f0b4aab2f4ef52efeeb",
|
||||
"zh:2d4283740e92ce1403875486cd5ff2c8acf9df28c190873ab4d769ce37db10c1",
|
||||
"zh:457e16d70075eae714a7df249d3ba42c2176f19b6750650152c56f33959028d9",
|
||||
"zh:49ee88371e355c00971eefee6b5001392431b47b3e760a5c649dda76f59fb8fa",
|
||||
"zh:614ad3bf07155ed8a5ced41dafb09042afbd1868490a379654b3e970def8e33d",
|
||||
"zh:75be7199d76987e7549e1f27439922973d1bf27353b44a593bfbbc2e3b9f698f",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:822c0a3bbada5e38099a379db8b2e339526843699627c3be3664cc3b3752bab7",
|
||||
"zh:af23af2f98a84695b25c8eba7028a81ad4aad63c44aefb79e01bbe2dc82e7f78",
|
||||
"zh:e36cac9960b7506d92925b667254322520966b9c3feb3ca6102e57a1fb9b1761",
|
||||
"zh:ffd1e096c1cc35de879c740a91918e9f06b627818a3cb4b1d87b829b54a6985f",
|
||||
"zh:888e14a24410d56b37212fbea373a3e0401d0ff8f8e4f4dd00ba8b29de9fed39",
|
||||
"zh:aa261925e8b152636a0886b3a2149864707632d836e98a88dacea6cfb6302082",
|
||||
"zh:ac10cefb4064b3bb63d4b0379624a416a45acf778eac0004466f726ead686196",
|
||||
"zh:b1a3c8b4d5b2dc9b510eac5e9e02665582862c24eb819ab74f44d3d880246d4f",
|
||||
"zh:c552e2fe5670b6d3ad9a5faf78e3a27197eeedbe2b13928d2c491fa509bc47c7",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.6.0"
|
||||
hashes = [
|
||||
"h1:R5Ucn26riKIEijcsiOMBR3uOAjuOMfI1x7XvH4P6B1w=",
|
||||
"zh:03360ed3ecd31e8c5dac9c95fe0858be50f3e9a0d0c654b5e504109c2159287d",
|
||||
"zh:1c67ac51254ba2a2bb53a25e8ae7e4d076103483f55f39b426ec55e47d1fe211",
|
||||
"zh:24a17bba7f6d679538ff51b3a2f378cedadede97af8a1db7dad4fd8d6d50f829",
|
||||
"zh:30ffb297ffd1633175d6545d37c2217e2cef9545a6e03946e514c59c0859b77d",
|
||||
"zh:454ce4b3dbc73e6775f2f6605d45cee6e16c3872a2e66a2c97993d6e5cbd7055",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:91df0a9fab329aff2ff4cf26797592eb7a3a90b4a0c04d64ce186654e0cc6e17",
|
||||
"zh:aa57384b85622a9f7bfb5d4512ca88e61f22a9cea9f30febaa4c98c68ff0dc21",
|
||||
"zh:c4a3e329ba786ffb6f2b694e1fd41d413a7010f3a53c20b432325a94fa71e839",
|
||||
"zh:e2699bc9116447f96c53d55f2a00570f982e6f9935038c3810603572693712d0",
|
||||
"zh:e747c0fd5d7684e5bfad8aa0ca441903f15ae7a98a737ff6aca24ba223207e2c",
|
||||
"zh:f1ca75f417ce490368f047b63ec09fd003711ae48487fba90b4aba2ccf71920e",
|
||||
]
|
||||
}
|
||||
|
204
core/authelia.tf
Normal file
204
core/authelia.tf
Normal file
@ -0,0 +1,204 @@
|
||||
module "authelia" {
|
||||
source = "../services/service"
|
||||
|
||||
name = "authelia"
|
||||
instance_count = 2
|
||||
priority = 70
|
||||
image = "authelia/authelia:4.37"
|
||||
args = ["--config", "$${NOMAD_TASK_DIR}/authelia.yml"]
|
||||
ingress = true
|
||||
service_port = 9999
|
||||
service_port_static = true
|
||||
use_wesher = var.use_wesher
|
||||
# metrics_port = 9959
|
||||
|
||||
env = {
|
||||
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE = "$${NOMAD_SECRETS_DIR}/ldap_password.txt"
|
||||
AUTHELIA_JWT_SECRET_FILE = "$${NOMAD_SECRETS_DIR}/jwt_secret.txt"
|
||||
AUTHELIA_SESSION_SECRET_FILE = "$${NOMAD_SECRETS_DIR}/session_secret.txt"
|
||||
AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE = "$${NOMAD_SECRETS_DIR}/storage_encryption_key.txt"
|
||||
AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE = "$${NOMAD_SECRETS_DIR}/mysql_password.txt"
|
||||
AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE = "$${NOMAD_SECRETS_DIR}/smtp_password.txt"
|
||||
AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE = "$${NOMAD_SECRETS_DIR}/oidc_hmac_secret.txt"
|
||||
AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY_FILE = "$${NOMAD_SECRETS_DIR}/oidc_issuer_private_key.txt"
|
||||
# AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_CERTIFICATE_CHAIN_FILE = "$${NOMAD_SECRETS_DIR}/oidc_issuer_certificate_chain.txt"
|
||||
}
|
||||
|
||||
use_mysql = true
|
||||
use_ldap = true
|
||||
use_redis = true
|
||||
use_smtp = true
|
||||
mysql_bootstrap = {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
service_tags = [
|
||||
# Configure traefik to add this middleware
|
||||
"traefik.http.middlewares.authelia.forwardAuth.address=http://authelia.nomad:$${NOMAD_PORT_main}/api/verify?rd=https%3A%2F%2Fauthelia.${var.base_hostname}%2F",
|
||||
"traefik.http.middlewares.authelia.forwardAuth.trustForwardHeader=true",
|
||||
"traefik.http.middlewares.authelia.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email",
|
||||
"traefik.http.middlewares.authelia-basic.forwardAuth.address=http://authelia.nomad:$${NOMAD_PORT_main}/api/verify?auth=basic",
|
||||
"traefik.http.middlewares.authelia-basic.forwardAuth.trustForwardHeader=true",
|
||||
"traefik.http.middlewares.authelia-basic.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email",
|
||||
]
|
||||
|
||||
templates = [
|
||||
{
|
||||
data = file("${path.module}/authelia.yml")
|
||||
dest = "authelia.yml"
|
||||
mount = false
|
||||
},
|
||||
{
|
||||
data = "{{ with nomadVar \"secrets/ldap\" }}{{ .admin_password }}{{ end }}"
|
||||
dest_prefix = "$${NOMAD_SECRETS_DIR}"
|
||||
dest = "ldap_password.txt"
|
||||
mount = false
|
||||
},
|
||||
{
|
||||
data = "{{ with nomadVar \"nomad/jobs/authelia\" }}{{ .jwt_secret }}{{ end }}"
|
||||
dest_prefix = "$${NOMAD_SECRETS_DIR}"
|
||||
dest = "jwt_secret.txt"
|
||||
mount = false
|
||||
},
|
||||
{
|
||||
data = "{{ with nomadVar \"nomad/jobs/authelia\" }}{{ .session_secret }}{{ end }}"
|
||||
dest_prefix = "$${NOMAD_SECRETS_DIR}"
|
||||
dest = "session_secret.txt"
|
||||
mount = false
|
||||
},
|
||||
{
|
||||
data = "{{ with nomadVar \"nomad/jobs/authelia\" }}{{ .storage_encryption_key }}{{ end }}"
|
||||
dest_prefix = "$${NOMAD_SECRETS_DIR}"
|
||||
dest = "storage_encryption_key.txt"
|
||||
mount = false
|
||||
},
|
||||
{
|
||||
data = "{{ with nomadVar \"nomad/jobs/authelia\" }}{{ .db_pass }}{{ end }}"
|
||||
dest_prefix = "$${NOMAD_SECRETS_DIR}"
|
||||
dest = "mysql_password.txt"
|
||||
mount = false
|
||||
},
|
||||
{
|
||||
data = "{{ with nomadVar \"nomad/jobs/authelia\" }}{{ .oidc_hmac_secret }}{{ end }}"
|
||||
dest_prefix = "$${NOMAD_SECRETS_DIR}"
|
||||
dest = "oidc_hmac_secret.txt"
|
||||
mount = false
|
||||
},
|
||||
{
|
||||
data = "{{ with nomadVar \"nomad/jobs/authelia\" }}{{ .oidc_issuer_private_key }}{{ end }}"
|
||||
dest_prefix = "$${NOMAD_SECRETS_DIR}"
|
||||
dest = "oidc_issuer_private_key.txt"
|
||||
mount = false
|
||||
},
|
||||
{
|
||||
data = "{{ with nomadVar \"nomad/jobs/authelia\" }}{{ .oidc_issuer_certificate_chain }}{{ end }}"
|
||||
dest_prefix = "$${NOMAD_SECRETS_DIR}"
|
||||
dest = "oidc_issuer_certificate_chain.txt"
|
||||
mount = false
|
||||
},
|
||||
{
|
||||
data = "{{ with nomadVar \"secrets/smtp\" }}{{ .password }}{{ end }}"
|
||||
dest_prefix = "$${NOMAD_SECRETS_DIR}"
|
||||
dest = "smtp_password.txt"
|
||||
mount = false
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "authelia" {
|
||||
name = "authelia"
|
||||
description = "Give access to shared authelia variables"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "authelia/*" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
path "secrets/authelia/*" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = module.authelia.job_id
|
||||
}
|
||||
}
|
||||
|
||||
# Give access to ldap secrets
|
||||
resource "nomad_acl_policy" "authelia_ldap_secrets" {
|
||||
name = "authelia-secrets-ldap"
|
||||
description = "Give access to LDAP secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/ldap" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = module.authelia.job_id
|
||||
}
|
||||
}
|
||||
|
||||
# Enable oidc for nomad clients
|
||||
module "nomad_oidc_client" {
|
||||
source = "./oidc_client"
|
||||
|
||||
name = "nomad"
|
||||
oidc_client_config = {
|
||||
description = "Nomad"
|
||||
authorization_policy = "two_factor"
|
||||
redirect_uris = [
|
||||
"https://nomad.${var.base_hostname}/oidc/callback",
|
||||
"https://nomad.${var.base_hostname}/ui/settings/tokens",
|
||||
]
|
||||
scopes = ["openid", "groups"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_auth_method" "nomad_authelia" {
|
||||
name = "authelia"
|
||||
type = "OIDC"
|
||||
token_locality = "global"
|
||||
max_token_ttl = "1h0m0s"
|
||||
default = true
|
||||
|
||||
config {
|
||||
oidc_discovery_url = "https://authelia.${var.base_hostname}"
|
||||
oidc_client_id = module.nomad_oidc_client.client_id
|
||||
oidc_client_secret = module.nomad_oidc_client.secret
|
||||
bound_audiences = ["nomad"]
|
||||
oidc_scopes = [
|
||||
"groups",
|
||||
"openid",
|
||||
]
|
||||
allowed_redirect_uris = [
|
||||
"https://nomad.${var.base_hostname}/oidc/callback",
|
||||
"https://nomad.${var.base_hostname}/ui/settings/tokens",
|
||||
]
|
||||
list_claim_mappings = {
|
||||
"groups" : "roles"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_binding_rule" "nomad_authelia_admin" {
|
||||
description = "engineering rule"
|
||||
auth_method = nomad_acl_auth_method.nomad_authelia.name
|
||||
selector = "\"nomad-deploy\" in list.roles"
|
||||
bind_type = "role"
|
||||
bind_name = "admin" # acls.nomad_acl_role.admin.name
|
||||
}
|
||||
|
||||
resource "nomad_acl_binding_rule" "nomad_authelia_deploy" {
|
||||
description = "engineering rule"
|
||||
auth_method = nomad_acl_auth_method.nomad_authelia.name
|
||||
selector = "\"nomad-deploy\" in list.roles"
|
||||
bind_type = "role"
|
||||
bind_name = "deploy" # acls.nomad_acl_role.deploy.name
|
||||
}
|
278
core/authelia.yml
Normal file
278
core/authelia.yml
Normal file
@ -0,0 +1,278 @@
|
||||
theme: auto
|
||||
|
||||
# jwt_secret: <file>
|
||||
|
||||
{{ with nomadVar "nomad/jobs" }}
|
||||
default_redirection_url: https://authelia.{{ .base_hostname }}/
|
||||
{{ end }}
|
||||
|
||||
## Set the default 2FA method for new users and for when a user has a preferred method configured that has been
|
||||
## disabled. This setting must be a method that is enabled.
|
||||
## Options are totp, webauthn, mobile_push.
|
||||
default_2fa_method: ""
|
||||
|
||||
server:
|
||||
host: 0.0.0.0
|
||||
port: {{ env "NOMAD_PORT_main" }}
|
||||
disable_healthcheck: false
|
||||
|
||||
log:
|
||||
## Level of verbosity for logs: info, debug, trace.
|
||||
level: debug
|
||||
|
||||
format: json
|
||||
|
||||
telemetry:
|
||||
metrics:
|
||||
enabled: false
|
||||
# address: '0.0.0.0:{{ env "NOMAD_PORT_metrics" }}'
|
||||
|
||||
totp:
|
||||
disable: false
|
||||
issuer: {{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}
|
||||
digits: 6
|
||||
|
||||
## The TOTP algorithm to use.
|
||||
## It is CRITICAL you read the documentation before changing this option:
|
||||
## https://www.authelia.com/c/totp#algorithm
|
||||
algorithm: sha1
|
||||
|
||||
webauthn:
|
||||
disable: false
|
||||
timeout: 60s
|
||||
display_name: {{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}
|
||||
user_verification: preferred
|
||||
|
||||
duo_api:
|
||||
disable: true
|
||||
# hostname:
|
||||
# integration_key:
|
||||
# secret_key:
|
||||
# enable_self_enrollment: false
|
||||
|
||||
authentication_backend:
|
||||
disable_reset_password: false
|
||||
|
||||
## Password Reset Options.
|
||||
password_reset:
|
||||
|
||||
## External reset password url that redirects the user to an external reset portal. This disables the internal reset
|
||||
## functionality.
|
||||
# TODO: not sure if this is needed, probably not?
|
||||
custom_url: ""
|
||||
|
||||
refresh_interval: 5m
|
||||
|
||||
ldap:
|
||||
implementation: custom
|
||||
|
||||
# stunnel url
|
||||
url: ldap://127.0.0.1:389
|
||||
timeout: 5s
|
||||
|
||||
# TODO: Maybe use stunnel for this
|
||||
start_tls: false
|
||||
|
||||
base_dn: {{ with nomadVar "nomad/jobs" }}{{ .ldap_base_dn }}{{ end }}
|
||||
additional_users_dn: ou=people
|
||||
additional_groups_dn: ou=groups
|
||||
|
||||
username_attribute: uid
|
||||
group_name_attribute: cn
|
||||
mail_attribute: mail
|
||||
display_name_attribute: displayName
|
||||
|
||||
# To allow sign in both with username and email, one can use a filter like
|
||||
# (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
|
||||
users_filter: "(&({username_attribute}={input})(objectClass=person))"
|
||||
# Only supported filter by lldap right now
|
||||
groups_filter: (member={dn})
|
||||
|
||||
## The username and password of the admin user.
|
||||
{{ with nomadVar "secrets/ldap" }}
|
||||
user: uid={{ .admin_user }},ou=people,{{ with nomadVar "nomad/jobs" }}{{ .ldap_base_dn }}{{ end }}
|
||||
{{ end }}
|
||||
# password set using secrets file
|
||||
# password: <secret>
|
||||
|
||||
password_policy:
|
||||
standard:
|
||||
enabled: false
|
||||
min_length: 8
|
||||
max_length: 0
|
||||
require_uppercase: true
|
||||
require_lowercase: true
|
||||
require_number: true
|
||||
require_special: true
|
||||
|
||||
zxcvbn:
|
||||
enabled: false
|
||||
min_score: 3
|
||||
|
||||
##
|
||||
## Access Control Configuration
|
||||
##
|
||||
## Access control is a list of rules defining the authorizations applied for one resource to users or group of users.
|
||||
##
|
||||
## If 'access_control' is not defined, ACL rules are disabled and the 'bypass' rule is applied, i.e., access is allowed
|
||||
## to anyone. Otherwise restrictions follow the rules defined.
|
||||
##
|
||||
## Note: One can use the wildcard * to match any subdomain.
|
||||
## It must stand at the beginning of the pattern. (example: *.mydomain.com)
|
||||
##
|
||||
## Note: You must put patterns containing wildcards between simple quotes for the YAML to be syntactically correct.
|
||||
##
|
||||
## Definition: A 'rule' is an object with the following keys: 'domain', 'subject', 'policy' and 'resources'.
|
||||
##
|
||||
## - 'domain' defines which domain or set of domains the rule applies to.
|
||||
##
|
||||
## - 'subject' defines the subject to apply authorizations to. This parameter is optional and matching any user if not
|
||||
## provided. If provided, the parameter represents either a user or a group. It should be of the form
|
||||
## 'user:<username>' or 'group:<groupname>'.
|
||||
##
|
||||
## - 'policy' is the policy to apply to resources. It must be either 'bypass', 'one_factor', 'two_factor' or 'deny'.
|
||||
##
|
||||
## - 'resources' is a list of regular expressions that matches a set of resources to apply the policy to. This parameter
|
||||
## is optional and matches any resource if not provided.
|
||||
##
|
||||
## Note: the order of the rules is important. The first policy matching (domain, resource, subject) applies.
|
||||
access_control:
|
||||
## Default policy can either be 'bypass', 'one_factor', 'two_factor' or 'deny'. It is the policy applied to any
|
||||
## resource if there is no policy to be applied to the user.
|
||||
default_policy: deny
|
||||
|
||||
networks:
|
||||
- name: internal
|
||||
networks:
|
||||
- 192.168.1.0/24
|
||||
- 192.168.2.0/24
|
||||
- 192.168.10.0/24
|
||||
- name: VPN
|
||||
networks: 192.168.5.0/24
|
||||
|
||||
rules:
|
||||
## Allow favicons on internal network
|
||||
- domain: '*.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}'
|
||||
resources:
|
||||
- '^/apple-touch-icon-precomposed\.png$'
|
||||
- '^/assets/safari-pinned-tab\.svg$'
|
||||
- '^/apple-touch-icon-180x180\.png$'
|
||||
- '^/apple-touch-icon\.png$'
|
||||
- '^/favicon\.ico$'
|
||||
networks:
|
||||
- internal
|
||||
policy: bypass
|
||||
|
||||
{{ range nomadVarList "authelia/access_control/service_rules" }}{{ with nomadVar .Path }}
|
||||
- domain: '{{ .name }}.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}'
|
||||
{{ .rule.Value | indent 6 }}
|
||||
{{ end }}{{ end }}
|
||||
## Rules applied to everyone
|
||||
- domain: '*.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}'
|
||||
networks:
|
||||
- internal
|
||||
policy: one_factor
|
||||
|
||||
- domain: '*.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}'
|
||||
policy: two_factor
|
||||
|
||||
- domain:
|
||||
# TODO: Drive these from Nomad variables
|
||||
- 'secure.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}'
|
||||
policy: two_factor
|
||||
|
||||
session:
|
||||
## The name of the session cookie.
|
||||
name: authelia_session
|
||||
domain: {{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}
|
||||
|
||||
# Stored in a secrets file
|
||||
# secret: <in file>
|
||||
|
||||
expiration: 1h
|
||||
inactivity: 5m
|
||||
remember_me_duration: 1M
|
||||
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
|
||||
# username: authelia
|
||||
# password: authelia
|
||||
# database_index: 0
|
||||
maximum_active_connections: 8
|
||||
minimum_idle_connections: 0
|
||||
|
||||
regulation:
|
||||
max_retries: 3
|
||||
find_time: 2m
|
||||
ban_time: 5m
|
||||
|
||||
##
|
||||
## Storage Provider Configuration
|
||||
##
|
||||
## The available providers are: `local`, `mysql`, `postgres`. You must use one and only one of these providers.
|
||||
storage:
|
||||
# encryption_key: <in file>
|
||||
|
||||
##
|
||||
## MySQL / MariaDB (Storage Provider)
|
||||
##
|
||||
mysql:
|
||||
host: 127.0.0.1
|
||||
port: 3306
|
||||
{{ with nomadVar "nomad/jobs/authelia" }}
|
||||
database: {{ .db_name }}
|
||||
username: {{ .db_user }}
|
||||
# password: <in_file>
|
||||
{{- end }}
|
||||
timeout: 5s
|
||||
|
||||
##
|
||||
## Notification Provider
|
||||
##
|
||||
## Notifications are sent to users when they require a password reset, a Webauthn registration or a TOTP registration.
|
||||
## The available providers are: filesystem, smtp. You must use only one of these providers.
|
||||
notifier:
|
||||
## You can disable the notifier startup check by setting this to true.
|
||||
disable_startup_check: true
|
||||
|
||||
{{ with nomadVar "secrets/smtp" }}
|
||||
smtp:
|
||||
host: {{ .server }}
|
||||
port: {{ .port }}
|
||||
username: {{ .user }}
|
||||
# password: <in file>
|
||||
|
||||
{{- end }}
|
||||
{{ with nomadVar "nomad/jobs/authelia" }}
|
||||
sender: "{{ .email_sender }}"
|
||||
|
||||
## Subject configuration of the emails sent. {title} is replaced by the text from the notifier.
|
||||
subject: "[Authelia] {title}"
|
||||
|
||||
## This address is used during the startup check to verify the email configuration is correct.
|
||||
## It's not important what it is except if your email server only allows local delivery.
|
||||
startup_check_address: test@iamthefij.com
|
||||
{{- end }}
|
||||
|
||||
identity_providers:
|
||||
oidc:
|
||||
# hmac_secret: <file>
|
||||
# issuer_private_key: <file>
|
||||
|
||||
clients:
|
||||
{{ range nomadVarList "authelia/access_control/oidc_clients" -}}
|
||||
{{- $name := (sprig_last (sprig_splitList "/" .Path)) -}}
|
||||
{{ "-" | indent 6 }}
|
||||
{{ with nomadVar .Path }}
|
||||
|
||||
{{- $im := .ItemsMap -}}
|
||||
{{- $im = sprig_set $im "redirect_uris" (.redirect_uris.Value | parseYAML) -}}
|
||||
{{- $im = sprig_set $im "scopes" (.scopes.Value | parseYAML) -}}
|
||||
{{- with nomadVar (printf "secrets/authelia/%s" $name) -}}
|
||||
{{- $im = sprig_set $im "secret" .secret_hash.Value -}}
|
||||
{{- end -}}
|
||||
{{ $im | toYAML | indent 8 }}
|
||||
{{ end }}
|
||||
{{ end }}
|
@ -2,20 +2,39 @@
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "1.4.16"
|
||||
version = "2.0.0"
|
||||
hashes = [
|
||||
"h1:PQxNPNmMVOErxryTWIJwr22k95DTSODmgRylqjc2TjI=",
|
||||
"h1:tyfjD/maKzb0RxxD9KWgLnkJu9lnYziYsQgGw85Giz8=",
|
||||
"zh:0d4fbb7030d9caac3b123e60afa44f50c83cc2a983e1866aec7f30414abe7b0e",
|
||||
"zh:0db080228e07c72d6d8ca8c45249d6f97cd0189fce82a77abbdcd49a52e57572",
|
||||
"zh:0df88393271078533a217654b96f0672c60eb59570d72e6aefcb839eea87a7a0",
|
||||
"zh:2883b335bb6044b0db6a00e602d6926c047c7f330294a73a90d089f98b24d084",
|
||||
"zh:390158d928009a041b3a182bdd82376b50530805ae92be2b84ed7c3b0fa902a0",
|
||||
"zh:7169b8f8df4b8e9659c49043848fd5f7f8473d0471f67815e8b04980f827f5ef",
|
||||
"zh:9417ee1383b1edd137024882d7035be4dca51fb4f725ca00ed87729086ec1755",
|
||||
"zh:a22910b5a29eeab5610350700b4899267c1b09b66cf21f7e4d06afc61d425800",
|
||||
"zh:a6185c9cd7aa458cd81861058ba568b6411fbac344373a20155e20256f4a7557",
|
||||
"zh:b6260ca9f034df1b47905b4e2a9c33b67dbf77224a694d5b10fb09ae92ffad4c",
|
||||
"zh:d87c12a6a7768f2b6c2a59495c7dc00f9ecc52b1b868331d4c284f791e278a1e",
|
||||
"h1:lIHIxA6ZmfyTGL3J9YIddhxlfit4ipSS09BLxkwo6L0=",
|
||||
"zh:09b897d64db293f9a904a4a0849b11ec1e3fff5c638f734d82ae36d8dc044b72",
|
||||
"zh:435cc106799290f64078ec24b6c59cb32b33784d609088638ed32c6d12121199",
|
||||
"zh:7073444bd064e8c4ec115ca7d9d7f030cc56795c0a83c27f6668bba519e6849a",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:79d238c35d650d2d83a439716182da63f3b2767e72e4cbd0b69cb13d9b1aebfc",
|
||||
"zh:7ef5f49344278fe0bbc5447424e6aa5425ff1821d010d944a444d7fa2c751acf",
|
||||
"zh:92179091638c8ba03feef371c4361a790190f9955caea1fa59de2055c701a251",
|
||||
"zh:a8a34398851761368eb8e7c171f24e55efa6e9fdbb5c455f6dec34dc17f631bc",
|
||||
"zh:b38fd5338625ebace5a4a94cea1a28b11bd91995d834e318f47587cfaf6ec599",
|
||||
"zh:b71b273a2aca7ad5f1e07c767b25b5a888881ba9ca93b30044ccc39c2937f03c",
|
||||
"zh:cd14357e520e0f09fb25badfb4f2ee37d7741afdc3ed47c7bcf54c1683772543",
|
||||
"zh:e05e025f4bb95138c3c8a75c636e97cd7cfd2fc1525b0c8bd097db8c5f02df6e",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.5.1"
|
||||
hashes = [
|
||||
"h1:VSnd9ZIPyfKHOObuQCaKfnjIHRtR7qTw19Rz8tJxm+k=",
|
||||
"zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64",
|
||||
"zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d",
|
||||
"zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831",
|
||||
"zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3",
|
||||
"zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b",
|
||||
"zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2",
|
||||
"zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865",
|
||||
"zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03",
|
||||
"zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602",
|
||||
"zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014",
|
||||
]
|
||||
}
|
||||
|
@ -1,20 +1,23 @@
|
||||
variable "config_data" {
|
||||
type = string
|
||||
description = "Plain text config file for blocky"
|
||||
}
|
||||
|
||||
job "blocky" {
|
||||
datacenters = ["dc1"]
|
||||
type = "system"
|
||||
type = "service"
|
||||
priority = 100
|
||||
|
||||
constraint {
|
||||
distinct_hosts = true
|
||||
}
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
# TODO: maybe switch to service job from system so we can use canary and autorollback
|
||||
# auto_revert = true
|
||||
auto_revert = true
|
||||
min_healthy_time = "60s"
|
||||
healthy_deadline = "5m"
|
||||
}
|
||||
|
||||
group "blocky" {
|
||||
# TODO: This must be updated to match the nubmer of servers (possibly grabbed from TF)
|
||||
# I am moving away from `system` jobs because of https://github.com/hashicorp/nomad/issues/12023
|
||||
count = 2
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
@ -24,70 +27,37 @@ job "blocky" {
|
||||
}
|
||||
|
||||
port "api" {
|
||||
# TODO: This may be broken. It seems we're exposing the loopback address which can't be reached
|
||||
# host_network = "loopback"
|
||||
%{~ if use_wesher ~}
|
||||
host_network = "wesher"
|
||||
%{~ endif ~}
|
||||
to = "4000"
|
||||
}
|
||||
|
||||
dns {
|
||||
# Set expclicit DNS servers because tasks, by default, use this task
|
||||
servers = ["1.1.1.1", "1.0.0.1"]
|
||||
servers = [
|
||||
"192.168.2.1",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
service {
|
||||
name = "blocky-dns"
|
||||
provider = "nomad"
|
||||
port = "dns"
|
||||
}
|
||||
|
||||
service {
|
||||
name = "blocky-api"
|
||||
provider = "nomad"
|
||||
port = "api"
|
||||
|
||||
meta {
|
||||
metrics_addr = "${NOMAD_ADDR_api}"
|
||||
}
|
||||
|
||||
tags = [
|
||||
"prometheus.scrape",
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.blocky-api.entryPoints=websecure",
|
||||
]
|
||||
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
local_service_port = 4000
|
||||
|
||||
expose {
|
||||
path {
|
||||
path = "/metrics"
|
||||
protocol = "http"
|
||||
local_path_port = 4000
|
||||
listener_port = "api"
|
||||
}
|
||||
}
|
||||
|
||||
upstreams {
|
||||
destination_name = "redis"
|
||||
local_bind_port = 6379
|
||||
}
|
||||
|
||||
upstreams {
|
||||
destination_name = "mysql-server"
|
||||
local_bind_port = 4040
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sidecar_task {
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 20
|
||||
memory_max = 50
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check {
|
||||
name = "api-health"
|
||||
port = "api"
|
||||
@ -95,6 +65,11 @@ job "blocky" {
|
||||
path = "/"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
|
||||
check_restart {
|
||||
limit = 3
|
||||
grace = "5m"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,37 +77,240 @@ job "blocky" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "ghcr.io/0xerr0r/blocky"
|
||||
image = "ghcr.io/0xerr0r/blocky:v0.24"
|
||||
args = ["-c", "$${NOMAD_TASK_DIR}/config.yml"]
|
||||
ports = ["dns", "api"]
|
||||
}
|
||||
|
||||
mount {
|
||||
type = "bind"
|
||||
target = "/app/config.yml"
|
||||
source = "app/config.yml"
|
||||
}
|
||||
action "refresh-lists" {
|
||||
command = "/app/blocky"
|
||||
args = ["lists", "refresh"]
|
||||
}
|
||||
|
||||
action "healthcheck" {
|
||||
command = "/app/blocky"
|
||||
args = ["healthcheck"]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 50
|
||||
memory_max = 100
|
||||
}
|
||||
|
||||
vault {
|
||||
policies = [
|
||||
"access-tables",
|
||||
"nomad-task",
|
||||
]
|
||||
memory = 75
|
||||
memory_max = 150
|
||||
}
|
||||
|
||||
template {
|
||||
data = var.config_data
|
||||
destination = "app/config.yml"
|
||||
data = <<EOF
|
||||
${file("${module_path}/config.yml")}
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/config.yml"
|
||||
splay = "1m"
|
||||
|
||||
wait {
|
||||
min = "10s"
|
||||
max = "20s"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ range nomadServices }}
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") .Name -}}
|
||||
{{ .Address }} {{ .Name }}.nomad
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/nomad.hosts"
|
||||
change_mode = "noop"
|
||||
|
||||
wait {
|
||||
min = "10s"
|
||||
max = "20s"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ if nomadVarExists "blocky_lists/user" }}
|
||||
{{ with nomadVar "blocky_lists/user" -}}
|
||||
{{ .block_list.Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/block"
|
||||
change_mode = "script"
|
||||
|
||||
change_script {
|
||||
command = "/app/blocky"
|
||||
args = ["lists", "refresh"]
|
||||
timeout = "20s"
|
||||
}
|
||||
|
||||
wait {
|
||||
min = "30s"
|
||||
max = "1m"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ if nomadVarExists "blocky_lists/user" }}
|
||||
{{ with nomadVar "blocky_lists/user" -}}
|
||||
{{ .allow_list.Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/allow"
|
||||
change_mode = "script"
|
||||
|
||||
change_script {
|
||||
command = "/app/blocky"
|
||||
args = ["lists", "refresh"]
|
||||
timeout = "20s"
|
||||
}
|
||||
|
||||
wait {
|
||||
min = "30s"
|
||||
max = "1m"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ if nomadVarExists "blocky_lists/terraform" }}
|
||||
{{ with nomadVar "blocky_lists/terraform" -}}
|
||||
{{ .smarttv_regex.Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/smarttv-regex.txt"
|
||||
change_mode = "script"
|
||||
|
||||
change_script {
|
||||
command = "/app/blocky"
|
||||
args = ["lists", "refresh"]
|
||||
timeout = "20s"
|
||||
}
|
||||
|
||||
wait {
|
||||
min = "10s"
|
||||
max = "20s"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ if nomadVarExists "blocky_lists/terraform" }}
|
||||
{{ with nomadVar "blocky_lists/terraform" -}}
|
||||
{{ .wemo.Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/wemo.txt"
|
||||
change_mode = "script"
|
||||
|
||||
change_script {
|
||||
command = "/app/blocky"
|
||||
args = ["lists", "refresh"]
|
||||
timeout = "20s"
|
||||
}
|
||||
|
||||
wait {
|
||||
min = "10s"
|
||||
max = "20s"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ if nomadVarExists "blocky_lists/terraform" }}
|
||||
{{ with nomadVar "blocky_lists/terraform" -}}
|
||||
{{ .sonos.Value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/sonos.txt"
|
||||
change_mode = "script"
|
||||
|
||||
change_script {
|
||||
command = "/app/blocky"
|
||||
args = ["lists", "refresh"]
|
||||
timeout = "20s"
|
||||
}
|
||||
|
||||
wait {
|
||||
min = "10s"
|
||||
max = "20s"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task "blocky-bootstrap" {
|
||||
task "stunnel" {
|
||||
driver = "docker"
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = true
|
||||
}
|
||||
|
||||
config {
|
||||
image = "iamthefij/stunnel:1.0.0"
|
||||
args = ["$${NOMAD_TASK_DIR}/stunnel.conf"]
|
||||
ports = ["tls"]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 20
|
||||
memory = 100
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
syslog = no
|
||||
foreground = yes
|
||||
delay = yes
|
||||
|
||||
[dns_server]
|
||||
# Dummy server to keep stunnel running if no mysql is present
|
||||
accept = 8053
|
||||
connect = 127.0.0.1:53
|
||||
ciphers = PSK
|
||||
PSKsecrets = {{ env "NOMAD_SECRETS_DIR" }}/mysql_stunnel_psk.txt
|
||||
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "mysql-tls" -}}
|
||||
[mysql_client]
|
||||
client = yes
|
||||
accept = 127.0.0.1:3306
|
||||
connect = {{ .Address }}:{{ .Port }}
|
||||
PSKsecrets = {{ env "NOMAD_SECRETS_DIR" }}/mysql_stunnel_psk.txt
|
||||
{{- end }}
|
||||
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "redis-blocky" -}}
|
||||
[redis_client]
|
||||
client = yes
|
||||
accept = 127.0.0.1:6379
|
||||
connect = {{ .Address }}:{{ .Port }}
|
||||
PSKsecrets = {{ env "NOMAD_SECRETS_DIR" }}/stunnel_psk.txt
|
||||
{{- end }}
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/stunnel.conf"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{- with nomadVar "secrets/mysql/allowed_psks/blocky" }}{{ .psk }}{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/mysql_stunnel_psk.txt"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{- with nomadVar "nomad/jobs/blocky/blocky/stunnel" -}}{{ .redis_stunnel_psk }}{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/stunnel_psk.txt"
|
||||
}
|
||||
}
|
||||
|
||||
task "mysql-bootstrap" {
|
||||
driver = "docker"
|
||||
|
||||
lifecycle {
|
||||
@ -145,25 +323,18 @@ job "blocky" {
|
||||
args = [
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
"/usr/bin/mysql --defaults-extra-file=$${NOMAD_SECRETS_DIR}/my.cnf < $${NOMAD_SECRETS_DIR}/bootstrap.sql",
|
||||
]
|
||||
}
|
||||
|
||||
vault {
|
||||
policies = [
|
||||
"access-tables",
|
||||
"nomad-task",
|
||||
"/usr/bin/timeout 2m /bin/bash -c \"until /usr/bin/mysql --defaults-extra-file=$${NOMAD_SECRETS_DIR}/my.cnf < $${NOMAD_SECRETS_DIR}/bootstrap.sql; do echo 'Retry in 10s'; sleep 10; done\" || true",
|
||||
]
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
[client]
|
||||
host={{ env "NOMAD_UPSTREAM_IP_mysql_server" }}
|
||||
port={{ env "NOMAD_UPSTREAM_PORT_mysql_server" }}
|
||||
host=127.0.0.1
|
||||
port=3306
|
||||
user=root
|
||||
{{ with secret "kv/data/mysql" }}
|
||||
password={{ .Data.data.root_password }}
|
||||
{{ with nomadVar "secrets/mysql" }}
|
||||
password={{ .mysql_root_password }}
|
||||
{{ end }}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/my.cnf"
|
||||
@ -171,21 +342,20 @@ password={{ .Data.data.root_password }}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ with secret "kv/data/blocky" -}}
|
||||
{{ if .Data.data.db_name -}}
|
||||
{{ $db_name := .Data.data.db_name }}
|
||||
{{ with nomadVar "nomad/jobs/blocky" }}{{ if .db_name -}}
|
||||
{{ $db_name := .db_name }}
|
||||
CREATE DATABASE IF NOT EXISTS `{{ $db_name }}`;
|
||||
CREATE USER IF NOT EXISTS '{{ .Data.data.db_user }}'@'%' IDENTIFIED BY '{{ .Data.data.db_pass }}';
|
||||
GRANT ALL ON `{{ $db_name }}`.* to '{{ .Data.data.db_user }}'@'%';
|
||||
{{ with secret "kv/data/grafana" -}}
|
||||
-- Add grafana read_only user
|
||||
CREATE USER IF NOT EXISTS '{{ .Data.data.db_user_ro }}'@'%' IDENTIFIED BY '{{ .Data.data.db_pass_ro }}';
|
||||
GRANT SELECT ON `{{ $db_name }}`.* to '{{ .Data.data.db_user_ro }}'@'%';
|
||||
{{ end -}}
|
||||
CREATE USER IF NOT EXISTS '{{ .db_user }}'@'%' IDENTIFIED BY '{{ .db_pass }}';
|
||||
GRANT ALL ON `{{ $db_name }}`.* to '{{ .db_user }}'@'%';
|
||||
|
||||
{{ with nomadService "grafana" }}{{ with nomadVar "nomad/jobs" -}}
|
||||
-- Grant grafana read_only user access to db
|
||||
GRANT SELECT ON `{{ $db_name }}`.* to '{{ .db_user_ro }}'@'%';
|
||||
{{ end }}{{ end -}}
|
||||
|
||||
{{ else -}}
|
||||
SELECT 'NOOP';
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ end -}}{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/bootstrap.sql"
|
||||
}
|
||||
|
@ -1,25 +1,88 @@
|
||||
variable "base_hostname" {
|
||||
type = string
|
||||
description = "Base hostname to serve content from"
|
||||
default = "dev.homelab"
|
||||
}
|
||||
|
||||
locals {
|
||||
config_data = templatefile(
|
||||
"${path.module}/config.yml",
|
||||
{
|
||||
"base_hostname" = var.base_hostname,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
resource "nomad_job" "blocky" {
|
||||
hcl2 {
|
||||
enabled = true
|
||||
vars = {
|
||||
"config_data" = local.config_data,
|
||||
jobspec = templatefile("${path.module}/blocky.nomad", {
|
||||
use_wesher = var.use_wesher,
|
||||
module_path = path.module,
|
||||
})
|
||||
}
|
||||
|
||||
# Generate secrets and policies for access to MySQL
|
||||
resource "nomad_acl_policy" "blocky_mysql_bootstrap_secrets" {
|
||||
name = "blocky-secrets-mysql"
|
||||
description = "Give access to MySQL secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/mysql" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
|
||||
jobspec = file("${path.module}/blocky.nomad")
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = "blocky"
|
||||
group = "blocky"
|
||||
task = "mysql-bootstrap"
|
||||
}
|
||||
}
|
||||
|
||||
resource "random_password" "blocky_mysql_psk" {
|
||||
length = 32
|
||||
override_special = "!@#%&*-_="
|
||||
}
|
||||
|
||||
resource "nomad_variable" "blocky_mysql_psk" {
|
||||
path = "secrets/mysql/allowed_psks/blocky"
|
||||
items = {
|
||||
psk = "blocky:${resource.random_password.blocky_mysql_psk.result}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "blocky_mysql_psk" {
|
||||
name = "blocky-secrets-mysql-psk"
|
||||
description = "Give access to MySQL PSK secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/mysql/allowed_psks/blocky" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = "blocky"
|
||||
group = "blocky"
|
||||
task = "stunnel"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_variable" "blocky_lists_terraform" {
|
||||
path = "blocky_lists/terraform"
|
||||
items = {
|
||||
smarttv_regex = file("${path.module}/list-smarttv-regex.txt")
|
||||
wemo = file("${path.module}/list-wemo.txt")
|
||||
sonos = file("${path.module}/list-sonos.txt")
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "blocky_lists" {
|
||||
name = "blocky-lists"
|
||||
description = "Give access Blocky lists"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "blocky_lists/*" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = "blocky"
|
||||
group = "blocky"
|
||||
task = "blocky"
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,58 @@
|
||||
bootstrapDns:
|
||||
ips:
|
||||
- 1.1.1.1
|
||||
- 1.0.0.1
|
||||
ports:
|
||||
dns: 53
|
||||
http: 4000
|
||||
|
||||
upstream:
|
||||
default:
|
||||
- 1.1.1.1
|
||||
- 1.0.0.1
|
||||
quad9:
|
||||
- 9.9.9.9
|
||||
- 149.112.112.112
|
||||
- 2620:fe::fe
|
||||
- 2620:fe::9
|
||||
- https://dns.quad9.net/dns-query
|
||||
- tcp-tls:dns.quad9.net
|
||||
quad9-unsecured:
|
||||
- 9.9.9.10
|
||||
- 149.112.112.10
|
||||
- 2620:fe::10
|
||||
- 2620:fe::fe:10
|
||||
- https://dns10.quad9.net/dns-query
|
||||
- tcp-tls:dns10.quad9.net
|
||||
# I must have ip v6 blocked or something
|
||||
connectIPVersion: v4
|
||||
|
||||
bootstrapDns:
|
||||
- upstream: 1.1.1.1
|
||||
- upstream: 1.0.0.1
|
||||
- upstream: 9.9.9.9
|
||||
- upstream: 149.112.112.112
|
||||
|
||||
|
||||
upstreams:
|
||||
init:
|
||||
strategy: fast
|
||||
groups:
|
||||
default:
|
||||
- https://dns.quad9.net/dns-query
|
||||
- tcp-tls:dns.quad9.net
|
||||
- https://one.one.one.one/dns-query
|
||||
- tcp-tls:one.one.one.one
|
||||
# cloudflare:
|
||||
# - 1.1.1.1
|
||||
# - 1.0.0.1
|
||||
# - 2606:4700:4700::1111
|
||||
# - 2606:4700:4700::1001
|
||||
# - https://one.one.one.one/dns-query
|
||||
# - tcp-tls:one.one.one.one
|
||||
# quad9:
|
||||
# - 9.9.9.9
|
||||
# - 149.112.112.112
|
||||
# - 2620:fe::fe
|
||||
# - 2620:fe::9
|
||||
# - https://dns.quad9.net/dns-query
|
||||
# - tcp-tls:dns.quad9.net
|
||||
# quad9-secured:
|
||||
# - 9.9.9.11
|
||||
# - 149.112.112.11
|
||||
# - 2620:fe::11
|
||||
# - 2620:fe::fe:11
|
||||
# - https://dns11.quad9.net/dns-query
|
||||
# - tcp-tls:dns11.quad9.net
|
||||
# quad9-unsecured:
|
||||
# - 9.9.9.10
|
||||
# - 149.112.112.10
|
||||
# - 2620:fe::10
|
||||
# - 2620:fe::fe:10
|
||||
# - https://dns10.quad9.net/dns-query
|
||||
# - tcp-tls:dns10.quad9.net
|
||||
|
||||
conditional:
|
||||
fallbackUpstream: false
|
||||
mapping:
|
||||
consul: {{ env "attr.unique.network.ip-address" }}:8600
|
||||
home.arpa: 192.168.2.1
|
||||
in-addr.arpa: 192.168.2.1
|
||||
iot: 192.168.2.1
|
||||
@ -33,6 +60,13 @@ conditional:
|
||||
thefij: 192.168.2.1
|
||||
.: 192.168.2.1
|
||||
|
||||
hostsFile:
|
||||
sources:
|
||||
- {{ env "NOMAD_TASK_DIR" }}/nomad.hosts
|
||||
hostsTTL: 30s
|
||||
loading:
|
||||
refreshPeriod: 30s
|
||||
|
||||
clientLookup:
|
||||
upstream: 192.168.2.1
|
||||
|
||||
@ -43,55 +77,66 @@ blocking:
|
||||
- http://sysctl.org/cameleon/hosts
|
||||
- https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
|
||||
- https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
|
||||
- https://hosts-file.net/ad_servers.txt
|
||||
smarttv:
|
||||
- https://perflyst.github.io/PiHoleBlocklist/SmartTV.txt
|
||||
- https://perflyst.github.io/PiHoleBlocklist/regex.list
|
||||
malware:
|
||||
- https://mirror1.malwaredomains.com/files/justdomains
|
||||
# - https://hosts-file.net/ad_servers.txt
|
||||
iot:
|
||||
- https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/SmartTV.txt
|
||||
- {{ env "NOMAD_TASK_DIR" }}/smarttv-regex.txt
|
||||
- {{ env "NOMAD_TASK_DIR" }}/wemo.txt
|
||||
- {{ env "NOMAD_TASK_DIR" }}/sonos.txt
|
||||
antisocial:
|
||||
- |
|
||||
facebook.com
|
||||
instagram.com
|
||||
reddit.com
|
||||
twitter.com
|
||||
youtube.com
|
||||
custom:
|
||||
- {{ env "NOMAD_TASK_DIR" }}/block
|
||||
|
||||
whiteLists:
|
||||
# Move to Gitea when deployed internally
|
||||
ads:
|
||||
{{ keyOrDefault "blocky/whitelists/ads" "# None" | indent 6 }}
|
||||
custom:
|
||||
- {{ env "NOMAD_TASK_DIR" }}/allow
|
||||
|
||||
clientGroupsBlock:
|
||||
default:
|
||||
- ads
|
||||
- malware
|
||||
- smarttv
|
||||
- custom
|
||||
192.168.3.1/24:
|
||||
- ads
|
||||
- iot
|
||||
- custom
|
||||
|
||||
customDNS:
|
||||
customTTL: 1h
|
||||
mapping:
|
||||
{{ with service "traefik" -}}
|
||||
{{ with nomadVar "nomad/jobs/blocky" }}{{ .mappings.Value | indent 4 }}{{ end }}
|
||||
# Catch all at top domain to traefik
|
||||
{{ with nomadService "traefik" -}}
|
||||
{{- $last := len . | subtract 1 -}}
|
||||
{{- $services := . -}}
|
||||
{{ keyOrDefault "global/base_hostname" "${base_hostname}" }}: {{ range $i := loop $last -}}
|
||||
{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}: {{ range $i := loop $last -}}
|
||||
{{- with index $services $i }}{{ .Address }},{{ end -}}
|
||||
{{- end -}}
|
||||
{{- with index . $last }}{{ .Address }}{{ end -}}
|
||||
{{- end }}
|
||||
# Other mappings
|
||||
{{ keyOrDefault "blocky/mappings" "# None" | indent 4 }}
|
||||
|
||||
prometheus:
|
||||
enable: true
|
||||
|
||||
{{ with service "redis" -}}
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "redis-blocky" -}}
|
||||
redis:
|
||||
address: {{ env "NOMAD_UPSTREAM_ADDR_redis" }}
|
||||
address: 127.0.0.1:6379
|
||||
# password: ""
|
||||
# database: 0
|
||||
connectionAttempts: 10
|
||||
connectionCooldown: 3s
|
||||
{{ end -}}
|
||||
|
||||
{{ with service "vault" -}}{{ with service "mysql-server" -}}
|
||||
{{ with secret "kv/data/blocky" -}}
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "mysql-tls" -}}
|
||||
{{ with nomadVar "nomad/jobs/blocky" -}}
|
||||
queryLog:
|
||||
type: mysql
|
||||
target: {{ .Data.data.db_user }}:{{ .Data.data.db_pass }}@tcp({{ env "NOMAD_UPSTREAM_ADDR_mysql_server" }})/{{ .Data.data.db_name }}?charset=utf8mb4&parseTime=True&loc=Local
|
||||
target: {{ .db_user }}:{{ .db_pass }}@tcp(127.0.0.1:3306)/{{ .db_name }}?charset=utf8mb4&parseTime=True&loc=Local
|
||||
logRetentionDays: 14
|
||||
{{ end -}}{{ end -}}{{ end -}}
|
||||
|
||||
port: 53
|
||||
httpPort: 4000
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
13
core/blocky/list-smarttv-regex.txt
Normal file
13
core/blocky/list-smarttv-regex.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# From: https://perflyst.github.io/PiHoleBlocklist/regex.list
|
||||
# Title: Perflyst's SmartTV Blocklist for Pi-hole - RegEx extension
|
||||
# Version: 13July2023v1
|
||||
# Samsung
|
||||
/(^|\.)giraffic\.com$/
|
||||
/(^|\.)internetat\.tv$/
|
||||
/(^|\.)pavv\.co\.kr$/
|
||||
/(^|\.)samsungcloudsolution\.net$/
|
||||
/(^|\.)samsungelectronics\.com$/
|
||||
/(^|\.)samsungrm\.net$/
|
||||
# /(^|\.)samsungotn\.net$/ # prevents updates
|
||||
# /(^|\.)samsungcloudcdn\.com$/ # prevents updates
|
||||
# /(^|\.)samsungcloudsolution\.com$/ # prevents internet connection
|
2
core/blocky/list-sonos.txt
Normal file
2
core/blocky/list-sonos.txt
Normal file
@ -0,0 +1,2 @@
|
||||
# Block Sonos devices from phoning home and allowing remote access
|
||||
/(^|\.)sonos\.com$/
|
8
core/blocky/list-wemo.txt
Normal file
8
core/blocky/list-wemo.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# Remote commands
|
||||
api.xbcs.net
|
||||
# Firmware updates
|
||||
fw.xbcs.net
|
||||
# TURN service
|
||||
nat.wemo2.com
|
||||
# Connectivity checks
|
||||
heartbeat.xwemo.com
|
5
core/blocky/vars.tf
Normal file
5
core/blocky/vars.tf
Normal file
@ -0,0 +1,5 @@
|
||||
variable "use_wesher" {
|
||||
type = bool
|
||||
description = "Indicates whether or not services should expose themselves on the wesher network"
|
||||
default = true
|
||||
}
|
@ -6,6 +6,7 @@ job "ddclient" {
|
||||
|
||||
task "ddclient" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "ghcr.io/linuxserver/ddclient:v3.10.0-ls104"
|
||||
|
||||
@ -16,28 +17,22 @@ job "ddclient" {
|
||||
}
|
||||
}
|
||||
|
||||
vault {
|
||||
policies = [
|
||||
"access-tables",
|
||||
"nomad-task",
|
||||
]
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
{{ with nomadVar "nomad/jobs/ddclient" -}}
|
||||
daemon=900
|
||||
ssl=yes
|
||||
use=web
|
||||
web=api.myip.com
|
||||
|
||||
protocol=cloudflare,
|
||||
zone={{ key "ddclient/zone" }},
|
||||
zone={{ .zone }},
|
||||
ttl=1,
|
||||
{{ with secret "kv/data/cloudflare" -}}
|
||||
login=token,
|
||||
password={{ .Data.data.domain_ddclient }}
|
||||
{{ end -}}
|
||||
password={{ .domain_ddclient }}
|
||||
|
||||
{{ key "ddclient/domain" }}
|
||||
{{ .domain }}
|
||||
{{- end }}
|
||||
EOH
|
||||
destination = "secrets/ddclient.conf"
|
||||
change_mode = "restart"
|
||||
|
@ -1,70 +1,56 @@
|
||||
job "metrics" {
|
||||
job "exporters" {
|
||||
datacenters = ["dc1"]
|
||||
type = "system"
|
||||
type = "service"
|
||||
priority = 55
|
||||
|
||||
constraint {
|
||||
distinct_hosts = true
|
||||
}
|
||||
|
||||
group "promtail" {
|
||||
# TODO: This must be updated to match the nubmer of servers (possibly grabbed from TF)
|
||||
# I am moving away from `system` jobs because of https://github.com/hashicorp/nomad/issues/1202
|
||||
count = 2
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
|
||||
port "promtail" {
|
||||
%{~ if use_wesher ~}
|
||||
host_network = "wesher"
|
||||
%{~ endif ~}
|
||||
to = 9080
|
||||
}
|
||||
}
|
||||
|
||||
service {
|
||||
name = "promtail"
|
||||
provider = "nomad"
|
||||
port = "promtail"
|
||||
|
||||
meta {
|
||||
metrics_addr = "${NOMAD_ADDR_promtail}"
|
||||
nomad_dc = "${NOMAD_DC}"
|
||||
nomad_node_name = "${node.unique.name}"
|
||||
nomad_dc = "$${NOMAD_DC}"
|
||||
nomad_node_name = "$${node.unique.name}"
|
||||
}
|
||||
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
local_service_port = 9080
|
||||
|
||||
upstreams {
|
||||
destination_name = "loki"
|
||||
local_bind_port = 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sidecar_task {
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/metrics"
|
||||
port = "promtail"
|
||||
interval = "10s"
|
||||
timeout = "10s"
|
||||
}
|
||||
tags = [
|
||||
"prometheus.scrape",
|
||||
]
|
||||
}
|
||||
|
||||
task "promtail" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "grafana/promtail:2.2.1"
|
||||
args = ["-config.file=/etc/promtail/promtail.yml"]
|
||||
ports = ["promtail"]
|
||||
meta = {
|
||||
"diun.sort_tags" = "semver"
|
||||
"diun.watch_repo" = true
|
||||
"diun.include_tags" = "^[0-9]+\\.[0-9]+\\.[0-9]+$"
|
||||
}
|
||||
|
||||
# Mount config
|
||||
mount {
|
||||
type = "bind"
|
||||
target = "/etc/promtail/promtail.yml"
|
||||
source = "local/promtail.yml"
|
||||
}
|
||||
config {
|
||||
image = "grafana/promtail:2.9.1"
|
||||
args = ["-config.file=$${NOMAD_TASK_DIR}/promtail.yml"]
|
||||
ports = ["promtail"]
|
||||
|
||||
# Bind mount host machine-id and log directories
|
||||
|
||||
@ -105,8 +91,9 @@ server:
|
||||
http_listen_port: 9080
|
||||
|
||||
clients:
|
||||
# loki upstream: {{ env "NOMAD_UPSTREAM_ADDR_loki" }}
|
||||
- url: http://{{ env "NOMAD_UPSTREAM_ADDR_loki" }}/loki/api/v1/push
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "loki" -}}
|
||||
- url: http://{{ .Address }}:{{ .Port }}/loki/api/v1/push
|
||||
{{- end }}
|
||||
|
||||
scrape_configs:
|
||||
|
||||
@ -137,13 +124,25 @@ scrape_configs:
|
||||
target_label: docker_compose_project
|
||||
- source_labels: ['__journal_com_docker_compose_service']
|
||||
target_label: docker_compose_service
|
||||
- source_labels: ['__journal_com_hashicorp_nomad_alloc_id']
|
||||
target_label: nomad_alloc_id
|
||||
- source_labels: ['__journal_com_hashicorp_nomad_job_id']
|
||||
target_label: nomad_job_id
|
||||
- source_labels: ['__journal_com_hashicorp_nomad_job_name']
|
||||
target_label: nomad_job_name
|
||||
- source_labels: ['__journal_com_hashicorp_nomad_node_name']
|
||||
target_label: nomad_node_name
|
||||
- source_labels: ['__journal_com_hashicorp_nomad_group_name']
|
||||
target_label: nomad_group_name
|
||||
- source_labels: ['__journal_com_hashicorp_nomad_task_name']
|
||||
target_label: nomad_task_name
|
||||
EOF
|
||||
destination = "local/promtail.yml"
|
||||
destination = "$${NOMAD_TASK_DIR}/promtail.yml"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 50
|
||||
memory = 100
|
||||
}
|
||||
}
|
||||
}
|
296
core/grafana.nomad
Normal file
296
core/grafana.nomad
Normal file
@ -0,0 +1,296 @@
|
||||
job "grafana" {
|
||||
datacenters = ["dc1"]
|
||||
|
||||
group "grafana" {
|
||||
count = 1
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
|
||||
port "web" {
|
||||
%{~ if use_wesher ~}
|
||||
host_network = "wesher"
|
||||
%{~ endif ~}
|
||||
to = 3000
|
||||
}
|
||||
}
|
||||
|
||||
ephemeral_disk {
|
||||
migrate = true
|
||||
sticky = true
|
||||
}
|
||||
|
||||
service {
|
||||
name = "grafana"
|
||||
provider = "nomad"
|
||||
port = "web"
|
||||
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.grafana.entryPoints=websecure",
|
||||
]
|
||||
}
|
||||
|
||||
task "stunnel" {
|
||||
driver = "docker"
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = true
|
||||
}
|
||||
|
||||
config {
|
||||
image = "iamthefij/stunnel:1.0.0"
|
||||
args = ["$${NOMAD_TASK_DIR}/stunnel.conf"]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 100
|
||||
memory = 100
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
syslog = no
|
||||
foreground = yes
|
||||
delay = yes
|
||||
|
||||
[mysql_client]
|
||||
client = yes
|
||||
accept = 127.0.0.1:3306
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "mysql-tls" -}}
|
||||
connect = {{ .Address }}:{{ .Port }}
|
||||
{{- end }}
|
||||
PSKsecrets = {{ env "NOMAD_SECRETS_DIR" }}/mysql_stunnel_psk.txt
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/stunnel.conf"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{- with nomadVar "secrets/mysql/allowed_psks/grafana" }}{{ .psk }}{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/mysql_stunnel_psk.txt"
|
||||
}
|
||||
}
|
||||
|
||||
task "mysql-bootstrap" {
|
||||
driver = "docker"
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
config {
|
||||
image = "mariadb:10"
|
||||
args = [
|
||||
"/usr/bin/timeout",
|
||||
"20m",
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
"until /usr/bin/mysql --defaults-extra-file=$${NOMAD_SECRETS_DIR}/my.cnf < $${NOMAD_SECRETS_DIR}/bootstrap.sql; do echo 'Retry in 10s'; sleep 10; done",
|
||||
]
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
[client]
|
||||
host=127.0.0.1
|
||||
port=3306
|
||||
user=root
|
||||
{{ with nomadVar "secrets/mysql" -}}
|
||||
password={{ .mysql_root_password }}
|
||||
{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/my.cnf"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ with nomadVar "nomad/jobs/grafana" -}}
|
||||
{{ if .db_name -}}
|
||||
CREATE DATABASE IF NOT EXISTS `{{ .db_name }}`;
|
||||
CREATE USER IF NOT EXISTS '{{ .db_user }}'@'%' IDENTIFIED BY '{{ .db_pass }}';
|
||||
GRANT ALL ON `{{ .db_name }}`.* to '{{ .db_user }}'@'%';
|
||||
-- Create Read Only user
|
||||
CREATE USER IF NOT EXISTS '{{ .db_user_ro }}'@'%' IDENTIFIED BY '{{ .db_pass_ro }}';
|
||||
{{ else -}}
|
||||
SELECT 'NOOP';
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/bootstrap.sql"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 50
|
||||
}
|
||||
}
|
||||
|
||||
task "grafana" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "grafana/grafana:10.0.10"
|
||||
args = ["--config", "$${NOMAD_ALLOC_DIR}/config/grafana.ini"]
|
||||
ports = ["web"]
|
||||
}
|
||||
|
||||
env = {
|
||||
"GF_INSTALL_PLUGINS" = "grafana-clock-panel,grafana-piechart-panel,grafana-polystat-panel,natel-discrete-panel",
|
||||
"GF_PATHS_CONFIG" = "$${NOMAD_ALLOC_DIR}/config/grafana.ini",
|
||||
"GF_PATHS_PROVISIONING" = "$${NOMAD_ALLOC_DIR}/config/provisioning",
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ with nomadVar "secrets/smtp" -}}
|
||||
GF_SMTP_USER={{ .user }}
|
||||
GF_SMTP_PASSWORD={{ .password }}
|
||||
{{ end -}}
|
||||
{{ with nomadVar "nomad/jobs/grafana" -}}
|
||||
GF_SECURITY_ADMIN_PASSWORD={{ .admin_pw }}
|
||||
GF_EXTERNAL_IMAGE_STORAGE_S3_ACCESS_KEY={{ .minio_access_key }}
|
||||
GF_EXTERNAL_IMAGE_STORAGE_S3_SECRET_KEY={{ .minio_secret_key }}
|
||||
GRAFANA_ALERT_EMAIL_ADDRESSES={{ .alert_email_addresses }}
|
||||
{{ if .db_name -}}
|
||||
# Database storage
|
||||
GF_DATABASE_TYPE=mysql
|
||||
GF_DATABASE_HOST=127.0.0.1:3306
|
||||
GF_DATABASE_NAME={{ .db_name }}
|
||||
GF_DATABASE_USER={{ .db_user }}
|
||||
GF_DATABASE_PASSWORD={{ .db_pass }}
|
||||
{{ end -}}
|
||||
SLACK_BOT_URL={{ .slack_bot_url }}
|
||||
SLACK_BOT_TOKEN={{ .slack_bot_token }}
|
||||
SLACK_HOOK_URL={{ .slack_hook_url }}
|
||||
{{ end -}}
|
||||
{{ with nomadVar "secrets/authelia/grafana" -}}
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_ID={{ .client_id }}
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET={{ .secret }}
|
||||
{{ end -}}
|
||||
EOF
|
||||
env = true
|
||||
destination = "secrets/conf.env"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 100
|
||||
memory = 200
|
||||
}
|
||||
}
|
||||
|
||||
task "grafana-reprovisioner" {
|
||||
driver = "docker"
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = true
|
||||
}
|
||||
|
||||
config {
|
||||
image = "alpine:3.17"
|
||||
args = ["$${NOMAD_TASK_DIR}/startup.sh"]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 100
|
||||
memory = 100
|
||||
}
|
||||
|
||||
env = {
|
||||
LOG_FILE = "/var/log/grafana_reloader.log"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
#! /bin/sh
|
||||
apk add curl
|
||||
touch "$LOG_FILE"
|
||||
exec tail -f "$LOG_FILE"
|
||||
EOF
|
||||
perms = "777"
|
||||
destination = "$${NOMAD_TASK_DIR}/startup.sh"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ with nomadVar "nomad/jobs/grafana" -}}
|
||||
GF_SECURITY_ADMIN_PASSWORD={{ .admin_pw }}
|
||||
{{ end -}}
|
||||
EOF
|
||||
env = true
|
||||
destination = "$${NOMAD_SECRETS_DIR}/conf.env"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
#! /bin/sh
|
||||
exec > "$LOG_FILE"
|
||||
exec 2>&1
|
||||
GRAFANA_URL=http://127.0.0.1:3000
|
||||
echo "Reload dashboards"
|
||||
curl -s -S --user admin:$GF_SECURITY_ADMIN_PASSWORD --request POST $GRAFANA_URL/api/admin/provisioning/dashboards/reload
|
||||
echo "Reload datasources"
|
||||
curl -s -S --user admin:$GF_SECURITY_ADMIN_PASSWORD --request POST $GRAFANA_URL/api/admin/provisioning/datasources/reload
|
||||
echo "Reload plugins"
|
||||
curl -s -S --user admin:$GF_SECURITY_ADMIN_PASSWORD --request POST $GRAFANA_URL/api/admin/provisioning/plugins/reload
|
||||
echo "Reload notifications"
|
||||
curl -s -S --user admin:$GF_SECURITY_ADMIN_PASSWORD --request POST $GRAFANA_URL/api/admin/provisioning/notifications/reload
|
||||
echo "Reload access-control"
|
||||
curl -s -S --user admin:$GF_SECURITY_ADMIN_PASSWORD --request POST $GRAFANA_URL/api/admin/provisioning/access-control/reload
|
||||
echo "Reload alerting"
|
||||
curl -s -S --user admin:$GF_SECURITY_ADMIN_PASSWORD --request POST $GRAFANA_URL/api/admin/provisioning/alerting/reload
|
||||
EOF
|
||||
change_mode = "noop"
|
||||
perms = "777"
|
||||
destination = "$${NOMAD_TASK_DIR}/reload_config.sh"
|
||||
}
|
||||
|
||||
%{ for config_file in fileset(join("/", [module_path, "grafana"]), "**") ~}
|
||||
template {
|
||||
data = <<EOF
|
||||
${file(join("/", [module_path, "grafana", config_file]))}
|
||||
EOF
|
||||
destination = "$${NOMAD_ALLOC_DIR}/config/${config_file}"
|
||||
perms = 777
|
||||
# Set owner to grafana uid
|
||||
# uid = 472
|
||||
# Change template delimeter for dashboard files that use json and have double curly braces and square braces
|
||||
%{ if endswith(config_file, ".json") ~}
|
||||
left_delimiter = "<<<<"
|
||||
right_delimiter = ">>>>"
|
||||
%{ endif }
|
||||
change_mode = "script"
|
||||
change_script {
|
||||
command = "/local/reload_config.sh"
|
||||
}
|
||||
}
|
||||
%{ endfor }
|
||||
|
||||
}
|
||||
|
||||
task "grafana-image-renderer" {
|
||||
driver = "docker"
|
||||
|
||||
constraint {
|
||||
attribute = "$${attr.cpu.arch}"
|
||||
value = "amd64"
|
||||
}
|
||||
|
||||
config {
|
||||
image = "grafana/grafana-image-renderer:3.6.1"
|
||||
ports = ["renderer"]
|
||||
}
|
||||
|
||||
env = {
|
||||
"RENDERING_MODE" = "clustered"
|
||||
"RENDERING_CLUSTERING_MODE" = "browser"
|
||||
"RENDERING_CLUSTERING_MAX_CONCURRENCY" = 5
|
||||
"RENDERING_CLUSTERING_TIMEOUT" = 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,8 +20,8 @@ data = /var/lib/grafana
|
||||
# Directory where grafana will automatically scan and look for plugins
|
||||
;plugins = /var/lib/grafana/plugins
|
||||
|
||||
# folder that contains provisioning config files that grafana will apply on startup and while running.
|
||||
provisioning = /etc/grafana/provisioning
|
||||
# folder that contains PROVISIONING config files that grafana will apply on startup and while running.
|
||||
provisioning = from_env
|
||||
|
||||
#################################### Server ####################################
|
||||
[server]
|
||||
@ -43,7 +43,7 @@ provisioning = /etc/grafana/provisioning
|
||||
|
||||
# The full public facing url you use in browser, used for redirects and emails
|
||||
# If you use reverse proxy and sub path specify full url (with sub path)
|
||||
root_url = https://grafana.thefij.rocks
|
||||
root_url = https://grafana.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}
|
||||
|
||||
# Log web requests
|
||||
;router_logging = false
|
||||
@ -258,15 +258,24 @@ log_queries =
|
||||
|
||||
#################################### Generic OAuth ##########################
|
||||
[auth.generic_oauth]
|
||||
;enabled = true
|
||||
;name = Cloudron
|
||||
enabled = true
|
||||
name = Authelia
|
||||
;allow_sign_up = true
|
||||
;client_id = some_id
|
||||
;client_secret = some_secret
|
||||
;scopes = user:email,read:org
|
||||
;auth_url = https://foo.bar/login/oauth/authorize
|
||||
;token_url = https://foo.bar/login/oauth/access_token
|
||||
;api_url = https://foo.bar/user
|
||||
client_id = from_env
|
||||
client_secret = from_env
|
||||
scopes = openid profile email groups
|
||||
auth_url = https://authelia.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}/api/oidc/authorization
|
||||
token_url = https://authelia.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}/api/oidc/token
|
||||
api_url = https://authelia.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}/api/oidc/userinfo
|
||||
login_attribute_path = preferred_username
|
||||
groups_attribute_path = groups
|
||||
name_attribute_path = name
|
||||
# Role attribute path is not working
|
||||
role_attribute_path = contains(groups[*], 'admin') && 'Admin' || contains(groups[*], 'grafana-admin') && 'Admin' || contains(groups[*], 'grafana-editor') && 'Editor' || contains(groups[*], 'developer') && 'Editor'
|
||||
allow_assign_grafana_admin = true
|
||||
skip_org_role_sync = true
|
||||
use_pkce = true
|
||||
|
||||
;team_ids =
|
||||
;allowed_organizations =
|
||||
|
||||
@ -281,9 +290,9 @@ log_queries =
|
||||
|
||||
#################################### Auth Proxy ##########################
|
||||
[auth.proxy]
|
||||
{{ with service "traefik" -}}
|
||||
enabled = true
|
||||
header_name = X-WEBAUTH-USER
|
||||
{{ with nomadService "traefik" -}}
|
||||
enabled = false
|
||||
header_name = Remote-User
|
||||
header_property = username
|
||||
auto_sign_up = true
|
||||
{{- $last := len . | subtract 1 -}}
|
||||
@ -432,7 +441,7 @@ enabled = true
|
||||
provider = s3
|
||||
|
||||
[external_image_storage.s3]
|
||||
endpoint = https://minio.thefij.rocks
|
||||
endpoint = https://minio.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}
|
||||
bucket = grafana-images
|
||||
region = us-east-1
|
||||
path_style_access = true
|
||||
@ -442,5 +451,5 @@ path_style_access = true
|
||||
|
||||
[rendering]
|
||||
# Since they are inside the same group, we can reference their bound ports
|
||||
server_url = http://localhost:8081/render
|
||||
callback_url = http://localhost:3000/
|
||||
server_url = http://127.0.0.1:8081/render
|
||||
callback_url = http://127.0.0.1:3000/
|
@ -104,7 +104,7 @@
|
||||
"uid": "Prometheus"
|
||||
},
|
||||
"exemplar": false,
|
||||
"expr": "sum(up{job=\"exporters\", consul_service=\"blocky-api\"})",
|
||||
"expr": "sum(nomad_client_allocs_running{exported_job=\"blocky\", task=\"blocky\"})",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"interval": "",
|
||||
@ -458,7 +458,7 @@
|
||||
"uid": "Prometheus"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "sum(blocky_blacklist_cache) / sum(up{job=\"exporters\", consul_service=\"blocky-api\"})",
|
||||
"expr": "sum(blocky_blacklist_cache) / sum(nomad_client_allocs_running{exported_job=\"blocky\", task=\"blocky\"})",
|
||||
"format": "table",
|
||||
"instant": false,
|
||||
"interval": "",
|
||||
@ -533,7 +533,7 @@
|
||||
"uid": "Prometheus"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "sum(go_memstats_sys_bytes{job=\"exporters\", consul_service=\"blocky-api\"})/sum(up{job=\"exporters\", consul_service=\"blocky-api\"})",
|
||||
"expr": "sum(go_memstats_sys_bytes{job=\"exporters\", consul_service=\"blocky-api\"})/sum(nomad_client_allocs_running{exported_job=\"blocky\", task=\"blocky\"})",
|
||||
"format": "table",
|
||||
"instant": false,
|
||||
"interval": "",
|
||||
@ -753,7 +753,7 @@
|
||||
"uid": "Prometheus"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "sum(blocky_cache_entry_count)/ sum(up{job=\"exporters\", consul_service=\"blocky-api\"})",
|
||||
"expr": "sum(blocky_cache_entry_count)/ sum(nomad_client_allocs_running{exported_job=\"blocky\", task=\"blocky\"})",
|
||||
"format": "table",
|
||||
"instant": false,
|
||||
"interval": "",
|
||||
@ -1162,7 +1162,7 @@
|
||||
"uid": "Prometheus"
|
||||
},
|
||||
"exemplar": false,
|
||||
"expr": "sum(time() -blocky_last_list_group_refresh)/ sum(up{job=\"exporters\", consul_service=\"blocky-api\"})",
|
||||
"expr": "sum(time() -blocky_last_list_group_refresh)/ sum(nomad_client_allocs_running{exported_job=\"blocky\", task=\"blocky\"})",
|
||||
"format": "table",
|
||||
"instant": true,
|
||||
"interval": "",
|
||||
@ -1224,7 +1224,7 @@
|
||||
"uid": "Prometheus"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "sum(blocky_prefetch_domain_name_cache_count)/ sum(up{job=\"exporters\", consul_service=\"blocky-api\"})",
|
||||
"expr": "sum(blocky_prefetch_domain_name_cache_count)/ sum(nomad_client_allocs_running{exported_job=\"blocky\", task=\"blocky\"})",
|
||||
"format": "table",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
@ -5,4 +5,4 @@ providers:
|
||||
type: file
|
||||
disableDeletion: false
|
||||
options:
|
||||
path: /etc/grafana/provisioning/dashboards/default
|
||||
path: {{ env "NOMAD_ALLOC_DIR" }}/config/provisioning/dashboards/default
|
19
core/grafana/provisioning/datasources/influxdb.yml
Normal file
19
core/grafana/provisioning/datasources/influxdb.yml
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: HASS Metrics
|
||||
url: "http://192.168.2.75:8086"
|
||||
type: influxdb
|
||||
access: proxy
|
||||
database: hass
|
||||
jsonData:
|
||||
dbName: hass
|
||||
|
||||
- name: Proxmox Metrics
|
||||
url: "http://192.168.2.75:8086"
|
||||
type: influxdb
|
||||
access: proxy
|
||||
database: proxmox
|
||||
jsonData:
|
||||
dbName: proxmox
|
@ -2,9 +2,11 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "loki" }}
|
||||
- name: Loki
|
||||
url: http://{{ env "NOMAD_UPSTREAM_ADDR_loki" }}
|
||||
url: "http://{{ .Address }}:{{ .Port }}"
|
||||
type: loki
|
||||
access: proxy
|
||||
isDefault: false
|
||||
version: 1
|
||||
{{ end }}
|
16
core/grafana/provisioning/datasources/mysql.yml
Normal file
16
core/grafana/provisioning/datasources/mysql.yml
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Blocky logs
|
||||
url: 127.0.0.1:3306
|
||||
# TODO: Looking for an acl friendly way to expose this since it's a variable in blocky setup
|
||||
database: blocky
|
||||
type: mysql
|
||||
isDefault: false
|
||||
version: 1
|
||||
{{ with nomadVar "nomad/jobs/grafana" -}}
|
||||
user: {{ .db_user_ro }}
|
||||
secureJsonData:
|
||||
password: {{ .db_pass_ro }}
|
||||
{{- end }}
|
@ -2,9 +2,11 @@
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "prometheus" }}
|
||||
- name: Prometheus
|
||||
url: http://{{ env "NOMAD_UPSTREAM_ADDR_prometheus" }}
|
||||
url: "http://{{ .Address }}:{{ .Port }}"
|
||||
type: prometheus
|
||||
access: proxy
|
||||
isDefault: true
|
||||
version: 1
|
||||
{{ end }}
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
{{ with secret "kv/data/grafana" -}}
|
||||
{{ with nomadVar "nomad/jobs/grafana" -}}
|
||||
notifiers:
|
||||
- name: Personal email
|
||||
type: email
|
||||
@ -7,5 +7,5 @@ notifiers:
|
||||
org_id: 1
|
||||
is_default: false
|
||||
settings:
|
||||
addresses: "{{ .Data.data.alert_email_addresses }}"
|
||||
addresses: "{{ .alert_email_addresses }}"
|
||||
{{ end -}}
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
{{ with secret "kv/data/slack" -}}
|
||||
{{ with nomadVar "nomad/jobs/grafana" -}}
|
||||
notifiers:
|
||||
- name: Slack Bot
|
||||
type: slack
|
||||
@ -7,11 +7,11 @@ notifiers:
|
||||
org_id: 1
|
||||
is_default: false
|
||||
settings:
|
||||
url: "{{ .Data.data.bot_url }}"
|
||||
url: "{{ .slack_bot_url }}"
|
||||
recipient: "#site-notifications"
|
||||
username: Grafana Alerts
|
||||
icon_url: https://grafana.iamthefij.com/public/img/grafana_icon.svg
|
||||
token: "{{ .Data.data.bot_token }}"
|
||||
token: "{{ .slack_bot_token }}"
|
||||
uploadImage: true
|
||||
mentionChannel: channel
|
||||
- name: Slack Hook
|
||||
@ -20,7 +20,7 @@ notifiers:
|
||||
org_id: 1
|
||||
is_default: true
|
||||
settings:
|
||||
url: "{{ .Data.data.hook_url }}"
|
||||
url: "{{ .slack_hook_url }}"
|
||||
icon_url: https://grafana.iamthefij.com/public/img/grafana_icon.svg
|
||||
uploadImage: true
|
||||
mentionChannel: channel
|
96
core/lego.nomad
Normal file
96
core/lego.nomad
Normal file
@ -0,0 +1,96 @@
|
||||
variable "lego_version" {
|
||||
default = "4.14.2"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "nomad_var_dirsync_version" {
|
||||
default = "0.0.2"
|
||||
type = string
|
||||
}
|
||||
|
||||
job "lego" {
|
||||
|
||||
type = "batch"
|
||||
|
||||
periodic {
|
||||
cron = "@weekly"
|
||||
prohibit_overlap = true
|
||||
}
|
||||
|
||||
group "main" {
|
||||
|
||||
network {
|
||||
dns {
|
||||
servers = ["1.1.1.1", "1.0.0.1"]
|
||||
}
|
||||
}
|
||||
|
||||
task "main" {
|
||||
driver = "exec"
|
||||
|
||||
config {
|
||||
command = "/bin/bash"
|
||||
args = ["${NOMAD_TASK_DIR}/start.sh"]
|
||||
}
|
||||
|
||||
artifact {
|
||||
source = "https://github.com/go-acme/lego/releases/download/v${var.lego_version}/lego_v${var.lego_version}_linux_${attr.cpu.arch}.tar.gz"
|
||||
}
|
||||
|
||||
artifact {
|
||||
source = "https://git.iamthefij.com/iamthefij/nomad-var-dirsync/releases/download/v${var.nomad_var_dirsync_version}/nomad-var-dirsync-linux-${attr.cpu.arch}.tar.gz"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
#! /bin/sh
|
||||
set -ex
|
||||
|
||||
cd ${NOMAD_TASK_DIR}
|
||||
|
||||
echo "Read certs from nomad vars"
|
||||
${NOMAD_TASK_DIR}/nomad-var-dirsync-linux-{{ env "attr.cpu.arch" }} -root-var=secrets/certs read .
|
||||
|
||||
action=run
|
||||
if [ -f /.lego/certificates/_.thefij.rocks.crt ]; then
|
||||
action=renew
|
||||
fi
|
||||
|
||||
echo "Attempt to $action certificates"
|
||||
${NOMAD_TASK_DIR}/lego \
|
||||
--accept-tos --pem \
|
||||
--email=iamthefij@gmail.com \
|
||||
--domains="*.thefij.rocks" \
|
||||
--dns="cloudflare" \
|
||||
$action \
|
||||
--$action-hook="${NOMAD_TASK_DIR}/nomad-var-dirsync-linux-{{ env "attr.cpu.arch" }} -root-var=secrets/certs write .lego" \
|
||||
EOH
|
||||
destination = "${NOMAD_TASK_DIR}/start.sh"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
{{ with nomadVar "nomad/jobs/lego" -}}
|
||||
CF_DNS_API_TOKEN={{ .domain_lego_dns }}
|
||||
CF_ZONE_API_TOKEN={{ .domain_lego_dns }}
|
||||
{{- end }}
|
||||
EOH
|
||||
destination = "secrets/cloudflare.env"
|
||||
env = true
|
||||
}
|
||||
|
||||
env = {
|
||||
NOMAD_ADDR = "unix:///secrets/api.sock"
|
||||
}
|
||||
|
||||
identity {
|
||||
env = true
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
core/lego.tf
Normal file
23
core/lego.tf
Normal file
@ -0,0 +1,23 @@
|
||||
resource "nomad_job" "lego" {
|
||||
jobspec = file("${path.module}/lego.nomad")
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "secrets_certs_write" {
|
||||
name = "secrets-certs-write"
|
||||
description = "Write certs to secrets store"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/certs/*" {
|
||||
capabilities = ["write", "read"]
|
||||
}
|
||||
path "secrets/certs" {
|
||||
capabilities = ["write", "read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
job_acl {
|
||||
job_id = "lego/*"
|
||||
}
|
||||
}
|
145
core/lldap.nomad
145
core/lldap.nomad
@ -1,145 +0,0 @@
|
||||
job "lldap" {
|
||||
datacenters = ["dc1"]
|
||||
type = "service"
|
||||
|
||||
group "lldap" {
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
|
||||
port "web" {
|
||||
host_network = "loopback"
|
||||
to = 17170
|
||||
}
|
||||
|
||||
port "ldap" {
|
||||
host_network = "loopback"
|
||||
to = 3890
|
||||
}
|
||||
}
|
||||
|
||||
volume "lldap-data" {
|
||||
type = "host"
|
||||
read_only = false
|
||||
source = "lldap-data"
|
||||
}
|
||||
|
||||
service {
|
||||
name = "lldap"
|
||||
port = "ldap"
|
||||
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
local_service_port = 3890
|
||||
|
||||
config {
|
||||
protocol = "tcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sidecar_task {
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
service {
|
||||
name = "ldap-admin"
|
||||
port = "web"
|
||||
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
local_service_port = 17170
|
||||
}
|
||||
}
|
||||
|
||||
sidecar_task {
|
||||
resources {
|
||||
cpu = 20
|
||||
memory = 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.ldap-admin.entryPoints=websecure",
|
||||
]
|
||||
}
|
||||
|
||||
task "lldap" {
|
||||
driver = "docker"
|
||||
|
||||
volume_mount {
|
||||
volume = "lldap-data"
|
||||
destination = "/data"
|
||||
read_only = false
|
||||
}
|
||||
|
||||
config {
|
||||
image = "nitnelave/lldap:v0.4"
|
||||
ports = ["ldap", "web"]
|
||||
args = ["run", "--config-file", "/lldap_config.toml"]
|
||||
|
||||
mount {
|
||||
type = "bind"
|
||||
source = "secrets/lldap_config.toml"
|
||||
target = "/lldap_config.toml"
|
||||
}
|
||||
}
|
||||
|
||||
vault {
|
||||
policies = [
|
||||
"access-tables",
|
||||
"nomad-task",
|
||||
]
|
||||
}
|
||||
|
||||
env = {
|
||||
"LLDAP_LDAP_PORT" = "${NOMAD_PORT_ldap}"
|
||||
"LLDAP_HTTP_PORT" = "${NOMAD_PORT_web}"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
database_url = "sqlite:///data/users.db?mode=rwc"
|
||||
key_file = "/data/private_key"
|
||||
ldap_base_dn = "{{ keyOrDefault "global/ldap/base_dn" "dc=example,dc=com" }}"
|
||||
{{ with secret "kv/data/lldap" -}}
|
||||
jwt_secret = "{{ .Data.data.jwt_secret }}"
|
||||
ldap_user_dn = "{{ .Data.data.admin_user }}"
|
||||
ldap_user_email = "{{ .Data.data.admin_email }}"
|
||||
ldap_user_pass = "{{ .Data.data.admin_password }}"
|
||||
{{ end -}}
|
||||
{{ with secret "kv/data/smtp" -}}
|
||||
[smtp_options]
|
||||
enable_password_reset = true
|
||||
server = "{{ .Data.data.server }}"
|
||||
port = {{ .Data.data.port }}
|
||||
tls_required = {{ .Data.data.tls }}
|
||||
user = "{{ .Data.data.user }}"
|
||||
password = "{{ .Data.data.password }}"
|
||||
{{ with secret "kv/data/lldap" -}}
|
||||
from = "{{ .Data.data.smtp_from }}"
|
||||
reply_to = "{{ .Data.data.smtp_reply_to }}"
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
EOH
|
||||
destination = "secrets/lldap_config.toml"
|
||||
change_mode = "restart"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 10
|
||||
memory = 200
|
||||
memory_max = 200
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,31 +3,27 @@ auth_enabled: false
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
|
||||
ingester:
|
||||
lifecycler:
|
||||
address: 127.0.0.1
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
replication_factor: 1
|
||||
final_sleep: 0s
|
||||
chunk_idle_period: 5m
|
||||
chunk_retain_period: 30s
|
||||
max_transfer_retries: 0
|
||||
common:
|
||||
ring:
|
||||
instance_addr: 127.0.0.1
|
||||
kvstore:
|
||||
store: inmemory
|
||||
replication_factor: 1
|
||||
path_prefix: /tmp/loki
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2018-04-15
|
||||
store: boltdb
|
||||
- from: 2020-05-15
|
||||
store: boltdb-shipper
|
||||
object_store: filesystem
|
||||
schema: v11
|
||||
index:
|
||||
prefix: index_
|
||||
period: 168h
|
||||
period: 24h
|
||||
|
||||
storage_config:
|
||||
boltdb:
|
||||
directory: {{ env "NOMAD_TASK_DIR" }}/index
|
||||
boltdb_shipper:
|
||||
active_index_directory: {{ env "NOMAD_TASK_DIR" }}/index
|
||||
|
||||
filesystem:
|
||||
directory: {{ env "NOMAD_TASK_DIR" }}/chunks
|
||||
@ -38,8 +34,8 @@ limits_config:
|
||||
reject_old_samples_max_age: 168h
|
||||
|
||||
chunk_store_config:
|
||||
max_look_back_period: 0s
|
||||
max_look_back_period: 168h
|
||||
|
||||
table_manager:
|
||||
retention_deletes_enabled: false
|
||||
retention_period: 0s
|
||||
retention_deletes_enabled: true
|
||||
retention_period: 168h
|
||||
|
24
core/loki.tf
Normal file
24
core/loki.tf
Normal file
@ -0,0 +1,24 @@
|
||||
module "loki" {
|
||||
source = "../services/service"
|
||||
detach = false
|
||||
|
||||
name = "loki"
|
||||
image = "grafana/loki:2.8.7"
|
||||
args = ["--config.file=$${NOMAD_TASK_DIR}/loki-config.yml"]
|
||||
|
||||
service_port = 3100
|
||||
ingress = true
|
||||
use_wesher = var.use_wesher
|
||||
service_check = {
|
||||
path = "/ready"
|
||||
}
|
||||
|
||||
sticky_disk = true
|
||||
templates = [
|
||||
{
|
||||
data = file("${path.module}/loki-config.yml")
|
||||
dest = "loki-config.yml"
|
||||
mount = false
|
||||
}
|
||||
]
|
||||
}
|
123
core/main.tf
123
core/main.tf
@ -1,136 +1,27 @@
|
||||
|
||||
module "blocky" {
|
||||
source = "./blocky"
|
||||
|
||||
base_hostname = var.base_hostname
|
||||
use_wesher = var.use_wesher
|
||||
|
||||
# Not in this module
|
||||
# depends_on = [module.databases]
|
||||
}
|
||||
|
||||
module "traefik" {
|
||||
source = "./traefik"
|
||||
|
||||
base_hostname = var.base_hostname
|
||||
}
|
||||
|
||||
module "nomad_login" {
|
||||
source = "IamTheFij/levant/nomad"
|
||||
version = "0.1.0"
|
||||
|
||||
template_path = "service.nomad"
|
||||
variables = {
|
||||
name = "nomad-login"
|
||||
image = "iamthefij/nomad-vault-login"
|
||||
service_port = 5000
|
||||
ingress = true
|
||||
ingress_rule = "Host(`nomad.thefij.rocks`) && PathPrefix(`/login`)"
|
||||
env = jsonencode({
|
||||
VAULT_ADDR = "http://$${attr.unique.network.ip-address}:8200",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module "metrics" {
|
||||
source = "./metrics"
|
||||
# Not in this module
|
||||
# depends_on = [module.databases]
|
||||
}
|
||||
|
||||
module "loki" {
|
||||
source = "IamTheFij/levant/nomad"
|
||||
version = "0.1.0"
|
||||
|
||||
template_path = "service.nomad"
|
||||
variables = {
|
||||
name = "loki"
|
||||
image = "grafana/loki:2.2.1"
|
||||
service_port = 3100
|
||||
ingress = true
|
||||
sticky_disk = true
|
||||
healthcheck = "/ready"
|
||||
templates = jsonencode([
|
||||
{
|
||||
data = file("${path.module}/loki-config.yml")
|
||||
dest = "/etc/loki/local-config.yaml"
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
resource "consul_config_entry" "loki_intent" {
|
||||
name = "loki"
|
||||
kind = "service-intentions"
|
||||
|
||||
config_json = jsonencode({
|
||||
Sources = [
|
||||
{
|
||||
Action = "allow"
|
||||
Name = "grafana"
|
||||
Precedence = 9
|
||||
Type = "consul"
|
||||
},
|
||||
{
|
||||
Action = "allow"
|
||||
Name = "promtail"
|
||||
Precedence = 9
|
||||
Type = "consul"
|
||||
},
|
||||
{
|
||||
Action = "allow"
|
||||
Name = "syslogng-promtail"
|
||||
Precedence = 9
|
||||
Type = "consul"
|
||||
},
|
||||
]
|
||||
})
|
||||
resource "nomad_job" "nomad-client-stalker" {
|
||||
# Stalker used to allow using Nomad service registry to identify nomad client hosts
|
||||
jobspec = file("${path.module}/nomad-client-stalker.nomad")
|
||||
}
|
||||
|
||||
resource "nomad_job" "syslog-ng" {
|
||||
jobspec = file("${path.module}/syslogng.nomad")
|
||||
|
||||
depends_on = [module.loki]
|
||||
}
|
||||
|
||||
resource "nomad_job" "ddclient" {
|
||||
jobspec = file("${path.module}/ddclient.nomad")
|
||||
}
|
||||
|
||||
resource "nomad_job" "lldap" {
|
||||
jobspec = file("${path.module}/lldap.nomad")
|
||||
}
|
||||
|
||||
resource "consul_config_entry" "syslogng_promtail_intent" {
|
||||
name = "syslogng-promtail"
|
||||
kind = "service-intentions"
|
||||
|
||||
config_json = jsonencode({
|
||||
Sources = [
|
||||
{
|
||||
Action = "allow"
|
||||
Name = "syslogng"
|
||||
Precedence = 9
|
||||
Type = "consul"
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
resource "consul_config_entry" "global_access" {
|
||||
name = "*"
|
||||
kind = "service-intentions"
|
||||
|
||||
config_json = jsonencode({
|
||||
Sources = [
|
||||
{
|
||||
Action = "allow"
|
||||
Name = "traefik"
|
||||
Precedence = 6
|
||||
Type = "consul"
|
||||
},
|
||||
{
|
||||
Action = "deny"
|
||||
Name = "*"
|
||||
Precedence = 5
|
||||
Type = "consul"
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
119
core/metrics.tf
Normal file
119
core/metrics.tf
Normal file
@ -0,0 +1,119 @@
|
||||
resource "nomad_job" "exporters" {
|
||||
jobspec = templatefile("${path.module}/exporters.nomad", {
|
||||
use_wesher = var.use_wesher,
|
||||
})
|
||||
}
|
||||
|
||||
resource "nomad_job" "prometheus" {
|
||||
jobspec = templatefile("${path.module}/prometheus.nomad", {
|
||||
use_wesher = var.use_wesher,
|
||||
})
|
||||
|
||||
detach = false
|
||||
}
|
||||
|
||||
resource "nomad_job" "grafana" {
|
||||
jobspec = templatefile("${path.module}/grafana.nomad", {
|
||||
module_path = path.module
|
||||
use_wesher = var.use_wesher
|
||||
})
|
||||
|
||||
depends_on = [nomad_job.prometheus]
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "grafana_smtp_secrets" {
|
||||
name = "grafana-secrets-smtp"
|
||||
description = "Give access to MySQL secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/smtp" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = "grafana"
|
||||
group = "grafana"
|
||||
task = "grafana"
|
||||
}
|
||||
}
|
||||
|
||||
# Generate secrets and policies for access to MySQL
|
||||
resource "nomad_acl_policy" "grafana_mysql_bootstrap_secrets" {
|
||||
name = "grafana-secrets-mysql"
|
||||
description = "Give access to MySQL secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/mysql" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = "grafana"
|
||||
group = "grafana"
|
||||
task = "mysql-bootstrap"
|
||||
}
|
||||
}
|
||||
|
||||
resource "random_password" "grafana_mysql_psk" {
|
||||
length = 32
|
||||
override_special = "!@#%&*-_="
|
||||
}
|
||||
|
||||
resource "nomad_variable" "grafana_mysql_psk" {
|
||||
path = "secrets/mysql/allowed_psks/grafana"
|
||||
items = {
|
||||
psk = "grafana:${resource.random_password.grafana_mysql_psk.result}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "grafana_mysql_psk" {
|
||||
name = "grafana-secrets-mysql-psk"
|
||||
description = "Give access to MySQL PSK secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/mysql/allowed_psks/grafana" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = "grafana"
|
||||
group = "grafana"
|
||||
task = "stunnel"
|
||||
}
|
||||
}
|
||||
|
||||
module "grafana_oidc" {
|
||||
source = "./oidc_client"
|
||||
|
||||
name = "grafana"
|
||||
oidc_client_config = {
|
||||
description = "Grafana"
|
||||
scopes = [
|
||||
"openid",
|
||||
"groups",
|
||||
"email",
|
||||
"profile",
|
||||
]
|
||||
redirect_uris = [
|
||||
"https://grafana.thefij.rocks/login/generic_oauth",
|
||||
]
|
||||
}
|
||||
|
||||
job_acl = {
|
||||
job_id = "grafana"
|
||||
group = "grafana"
|
||||
task = "grafana"
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/consul" {
|
||||
version = "2.15.0"
|
||||
hashes = [
|
||||
"h1:o+Su3YqeOkHgf86GEArIVDZfaZQphYFjAOwpi/b0bzs=",
|
||||
"h1:tAb2gwW+oZ8/t2j7lExdqpNrxmaWsHbyA2crFWClPb0=",
|
||||
"zh:0bd2a9873099d89bd52e9eee623dd20ccb275d1e2f750da229a53a4d5b23450c",
|
||||
"zh:1c9f87d4d97b2c61d006c0bef159d61d2a661a103025f8276ebbeb000129f931",
|
||||
"zh:25b73a34115255c464be10a53f2510c4a1db958a71be31974d30654d5472e624",
|
||||
"zh:32fa31329731db2bf4b7d0f09096416ca146f05b58f4482bbd4ee0f28cefbbcc",
|
||||
"zh:59136b73d3abe7cc5b06d9e12d123ad21298ca86ed49a4060a3cd7c2a28a74a1",
|
||||
"zh:a191f3210773ca25c543a92f2d392b85e6a053d596293655b1f25b33eb843b4c",
|
||||
"zh:b8b6033cf0687eadc1099f11d9fb2ca9429ff40c2d85bd6cb047c0f6bc5d5d8d",
|
||||
"zh:bb7d67ed28aa9b28fc5154161af003383f940b2beda0d4577857cad700f39cd1",
|
||||
"zh:be615288f59327b975532a1999deab60a022e6819fe80e5a32526155210ecbba",
|
||||
"zh:de1e3d5c34eef87eb301e74717754babb6dc8e19e3a964919e1165c5a076a719",
|
||||
"zh:eb8c61b20d8ce2bfff9f735ca8456a0d6368af13aa1f43866f61c70f88cc491c",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "1.4.16"
|
||||
hashes = [
|
||||
"h1:PQxNPNmMVOErxryTWIJwr22k95DTSODmgRylqjc2TjI=",
|
||||
"h1:tyfjD/maKzb0RxxD9KWgLnkJu9lnYziYsQgGw85Giz8=",
|
||||
"zh:0d4fbb7030d9caac3b123e60afa44f50c83cc2a983e1866aec7f30414abe7b0e",
|
||||
"zh:0db080228e07c72d6d8ca8c45249d6f97cd0189fce82a77abbdcd49a52e57572",
|
||||
"zh:0df88393271078533a217654b96f0672c60eb59570d72e6aefcb839eea87a7a0",
|
||||
"zh:2883b335bb6044b0db6a00e602d6926c047c7f330294a73a90d089f98b24d084",
|
||||
"zh:390158d928009a041b3a182bdd82376b50530805ae92be2b84ed7c3b0fa902a0",
|
||||
"zh:7169b8f8df4b8e9659c49043848fd5f7f8473d0471f67815e8b04980f827f5ef",
|
||||
"zh:9417ee1383b1edd137024882d7035be4dca51fb4f725ca00ed87729086ec1755",
|
||||
"zh:a22910b5a29eeab5610350700b4899267c1b09b66cf21f7e4d06afc61d425800",
|
||||
"zh:a6185c9cd7aa458cd81861058ba568b6411fbac344373a20155e20256f4a7557",
|
||||
"zh:b6260ca9f034df1b47905b4e2a9c33b67dbf77224a694d5b10fb09ae92ffad4c",
|
||||
"zh:d87c12a6a7768f2b6c2a59495c7dc00f9ecc52b1b868331d4c284f791e278a1e",
|
||||
]
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
job "grafana" {
|
||||
datacenters = ["dc1"]
|
||||
|
||||
group "grafana" {
|
||||
count = 1
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
|
||||
port "web" {
|
||||
host_network = "loopback"
|
||||
to = 3000
|
||||
}
|
||||
|
||||
port "renderer" {
|
||||
host_network = "loopback"
|
||||
to = 8081
|
||||
}
|
||||
}
|
||||
|
||||
ephemeral_disk {
|
||||
migrate = true
|
||||
sticky = true
|
||||
}
|
||||
|
||||
service {
|
||||
name = "grafana"
|
||||
port = "web"
|
||||
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
local_service_port = 3000
|
||||
|
||||
upstreams {
|
||||
destination_name = "prometheus"
|
||||
local_bind_port = 9090
|
||||
}
|
||||
|
||||
upstreams {
|
||||
destination_name = "loki"
|
||||
local_bind_port = 3100
|
||||
}
|
||||
|
||||
upstreams {
|
||||
destination_name = "mysql-server"
|
||||
local_bind_port = 6060
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sidecar_task {
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 50
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/"
|
||||
port = "web"
|
||||
interval = "10s"
|
||||
timeout = "10s"
|
||||
}
|
||||
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.grafana.entryPoints=websecure",
|
||||
]
|
||||
}
|
||||
|
||||
task "grafana-bootstrap" {
|
||||
driver = "docker"
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
config {
|
||||
image = "mariadb:10"
|
||||
args = [
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
"/usr/bin/mysql --defaults-extra-file=$${NOMAD_SECRETS_DIR}/my.cnf < $${NOMAD_SECRETS_DIR}/bootstrap.sql",
|
||||
]
|
||||
}
|
||||
|
||||
vault {
|
||||
policies = [
|
||||
"access-tables",
|
||||
"nomad-task",
|
||||
]
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
[client]
|
||||
host={{ env "NOMAD_UPSTREAM_IP_mysql_server" }}
|
||||
port={{ env "NOMAD_UPSTREAM_PORT_mysql_server" }}
|
||||
user=root
|
||||
{{ with secret "kv/data/mysql" }}
|
||||
password={{ .Data.data.root_password }}
|
||||
{{ end }}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/my.cnf"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ with secret "kv/data/grafana" -}}
|
||||
{{ if .Data.data.db_name -}}
|
||||
CREATE DATABASE IF NOT EXISTS `{{ .Data.data.db_name }}`;
|
||||
CREATE USER IF NOT EXISTS '{{ .Data.data.db_user }}'@'%' IDENTIFIED BY '{{ .Data.data.db_pass }}';
|
||||
GRANT ALL ON `{{ .Data.data.db_name }}`.* to '{{ .Data.data.db_user }}'@'%';
|
||||
-- Add grafana read_only user
|
||||
CREATE USER IF NOT EXISTS '{{ .Data.data.db_user_ro }}'@'%' IDENTIFIED BY '{{ .Data.data.db_pass_ro }}';
|
||||
{{ else -}}
|
||||
SELECT 'NOOP';
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/bootstrap.sql"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 50
|
||||
}
|
||||
}
|
||||
|
||||
task "grafana" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "grafana/grafana:9.2.4"
|
||||
ports = ["web"]
|
||||
|
||||
mount {
|
||||
type = "bind"
|
||||
target = "/etc/grafana"
|
||||
source = "local/config"
|
||||
}
|
||||
}
|
||||
|
||||
env = {
|
||||
"GF_INSTALL_PLUGINS" = "grafana-clock-panel,grafana-piechart-panel,grafana-polystat-panel,natel-discrete-panel",
|
||||
}
|
||||
|
||||
vault {
|
||||
policies = [
|
||||
"access-tables",
|
||||
"nomad-task",
|
||||
]
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ with secret "kv/data/grafana" -}}
|
||||
GF_SECURITY_ADMIN_PASSWORD={{ .Data.data.admin_pw }}
|
||||
GF_SMTP_USER={{ .Data.data.smtp_user }}
|
||||
GF_SMTP_PASSWORD={{ .Data.data.smtp_password }}
|
||||
GF_EXTERNAL_IMAGE_STORAGE_S3_ACCESS_KEY={{ .Data.data.minio_access_key }}
|
||||
GF_EXTERNAL_IMAGE_STORAGE_S3_SECRET_KEY={{ .Data.data.minio_secret_key }}
|
||||
GRAFANA_ALERT_EMAIL_ADDRESSES={{ .Data.data.alert_email_addresses }}
|
||||
{{ if .Data.data.db_name -}}
|
||||
# Database storage
|
||||
GF_DATABASE_TYPE=mysql
|
||||
GF_DATABASE_HOST={{ env "NOMAD_UPSTREAM_ADDR_mysql_server" }}
|
||||
GF_DATABASE_NAME={{ .Data.data.db_name }}
|
||||
GF_DATABASE_USER={{ .Data.data.db_user }}
|
||||
GF_DATABASE_PASSWORD={{ .Data.data.db_pass }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
{{ with secret "kv/data/slack" -}}
|
||||
SLACK_BOT_URL={{ .Data.data.bot_url }}
|
||||
SLACK_BOT_TOKEN={{ .Data.data.bot_token }}
|
||||
SLACK_HOOK_URL={{ .Data.data.hook_url }}
|
||||
{{ end -}}
|
||||
EOF
|
||||
env = true
|
||||
destination = "secrets/conf.env"
|
||||
}
|
||||
|
||||
%{ for config_file in fileset(join("/", [module_path, "grafana"]), "**") ~}
|
||||
template {
|
||||
data = <<EOF
|
||||
${file(join("/", [module_path, "grafana", config_file]))}
|
||||
EOF
|
||||
change_mode = "signal"
|
||||
change_signal = "SIGHUP"
|
||||
destination = "local/config/${config_file}"
|
||||
perms = 777
|
||||
# Set owner to grafana uid
|
||||
# uid = 472
|
||||
# Change template delimeter for dashboard files that use json and have double curly braces and square braces
|
||||
%{ if length(regexall("dashboard", config_file)) > 0 ~}
|
||||
left_delimiter = "<<<<"
|
||||
right_delimiter = ">>>>"
|
||||
%{ endif }
|
||||
}
|
||||
%{ endfor }
|
||||
|
||||
resources {
|
||||
cpu = 100
|
||||
memory = 200
|
||||
}
|
||||
}
|
||||
|
||||
task "grafana-image-renderer" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "grafana/grafana-image-renderer:3.6.1"
|
||||
ports = ["renderer"]
|
||||
}
|
||||
|
||||
env = {
|
||||
"RENDERING_MODE" = "clustered"
|
||||
"RENDERING_CLUSTERING_MODE" = "browser"
|
||||
"RENDERING_CLUSTERING_MAX_CONCURRENCY" = 5
|
||||
"RENDERING_CLUSTERING_TIMEOUT" = 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,783 +0,0 @@
|
||||
{
|
||||
"__inputs": [
|
||||
{
|
||||
"name": "DS_PROMETHEUS",
|
||||
"label": "Prometheus",
|
||||
"description": "",
|
||||
"type": "datasource",
|
||||
"pluginId": "prometheus",
|
||||
"pluginName": "Prometheus"
|
||||
}
|
||||
],
|
||||
"__requires": [
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "7.5.5"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "graph",
|
||||
"name": "Graph",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "piechart",
|
||||
"name": "Pie chart v2",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "prometheus",
|
||||
"name": "Prometheus",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "singlestat",
|
||||
"name": "Singlestat",
|
||||
"version": ""
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Traefik dashboard prometheus",
|
||||
"editable": true,
|
||||
"gnetId": 4475,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"iteration": 1620932097756,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"datasource": null,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 10,
|
||||
"title": "$backend stats",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"cacheTimeout": null,
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"decimals": 0,
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
"id": 2,
|
||||
"interval": null,
|
||||
"links": [],
|
||||
"maxDataPoints": 3,
|
||||
"options": {
|
||||
"displayLabels": [],
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "table",
|
||||
"placement": "right",
|
||||
"values": [
|
||||
"value",
|
||||
"percent"
|
||||
]
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"text": {}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "traefik_service_requests_total{service=\"$service\"}",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{method}} : {{code}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "$service return code",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"cacheTimeout": null,
|
||||
"colorBackground": false,
|
||||
"colorValue": false,
|
||||
"colors": [
|
||||
"#299c46",
|
||||
"rgba(237, 129, 40, 0.89)",
|
||||
"#d44a3a"
|
||||
],
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
},
|
||||
"format": "ms",
|
||||
"gauge": {
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"show": false,
|
||||
"thresholdLabels": false,
|
||||
"thresholdMarkers": true
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 1
|
||||
},
|
||||
"id": 4,
|
||||
"interval": null,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
{
|
||||
"name": "value to text",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"name": "range to text",
|
||||
"value": 2
|
||||
}
|
||||
],
|
||||
"maxDataPoints": 100,
|
||||
"nullPointMode": "connected",
|
||||
"nullText": null,
|
||||
"postfix": "",
|
||||
"postfixFontSize": "50%",
|
||||
"prefix": "",
|
||||
"prefixFontSize": "50%",
|
||||
"rangeMaps": [
|
||||
{
|
||||
"from": "null",
|
||||
"text": "N/A",
|
||||
"to": "null"
|
||||
}
|
||||
],
|
||||
"sparkline": {
|
||||
"fillColor": "rgba(31, 118, 189, 0.18)",
|
||||
"full": false,
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": true
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "sum(traefik_service_request_duration_seconds_sum{service=\"$service\"}) / sum(traefik_service_requests_total{service=\"$service\"}) * 1000",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": "",
|
||||
"title": "$service response time",
|
||||
"type": "singlestat",
|
||||
"valueFontSize": "80%",
|
||||
"valueMaps": [
|
||||
{
|
||||
"op": "=",
|
||||
"text": "N/A",
|
||||
"value": "null"
|
||||
}
|
||||
],
|
||||
"valueName": "avg"
|
||||
},
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": true,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"id": 3,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
"avg": true,
|
||||
"current": false,
|
||||
"max": true,
|
||||
"min": true,
|
||||
"rightSide": true,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": true
|
||||
},
|
||||
"lines": false,
|
||||
"linewidth": 1,
|
||||
"links": [],
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"alertThreshold": true
|
||||
},
|
||||
"percentage": false,
|
||||
"pluginVersion": "7.5.5",
|
||||
"pointradius": 5,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "sum(rate(traefik_service_requests_total{service=\"$service\"}[5m]))",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "Total requests $service",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeRegions": [],
|
||||
"timeShift": null,
|
||||
"title": "Total requests over 5min $service",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false,
|
||||
"alignLevel": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": null,
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 15
|
||||
},
|
||||
"id": 12,
|
||||
"panels": [],
|
||||
"title": "Global stats",
|
||||
"type": "row"
|
||||
},
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": true,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"id": 5,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
"avg": false,
|
||||
"current": true,
|
||||
"max": true,
|
||||
"min": true,
|
||||
"rightSide": true,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": true
|
||||
},
|
||||
"lines": false,
|
||||
"linewidth": 1,
|
||||
"links": [],
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"alertThreshold": true
|
||||
},
|
||||
"percentage": false,
|
||||
"pluginVersion": "7.5.5",
|
||||
"pointradius": 5,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": true,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "rate(traefik_entrypoint_requests_total{entrypoint=~\"$entrypoint\",code=\"200\"}[5m])",
|
||||
"format": "time_series",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{method}} : {{code}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeRegions": [],
|
||||
"timeShift": null,
|
||||
"title": "Status code 200 over 5min",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false,
|
||||
"alignLevel": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": true,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 16
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"id": 6,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
"avg": false,
|
||||
"current": true,
|
||||
"max": true,
|
||||
"min": true,
|
||||
"rightSide": true,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": true
|
||||
},
|
||||
"lines": false,
|
||||
"linewidth": 1,
|
||||
"links": [],
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"alertThreshold": true
|
||||
},
|
||||
"percentage": false,
|
||||
"pluginVersion": "7.5.5",
|
||||
"pointradius": 5,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": true,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"expr": "rate(traefik_entrypoint_requests_total{entrypoint=~\"$entrypoint\",code!=\"200\"}[5m])",
|
||||
"format": "time_series",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{ method }} : {{code}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeRegions": [],
|
||||
"timeShift": null,
|
||||
"title": "Others status code over 5min",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false,
|
||||
"alignLevel": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"cacheTimeout": null,
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"decimals": 0,
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 23
|
||||
},
|
||||
"id": 7,
|
||||
"interval": null,
|
||||
"links": [],
|
||||
"maxDataPoints": 3,
|
||||
"options": {
|
||||
"displayLabels": [],
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "table",
|
||||
"placement": "right",
|
||||
"values": [
|
||||
"value"
|
||||
]
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"sum"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"text": {}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "sum(rate(traefik_service_requests_total[5m])) by (service) ",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{ service }}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Requests by service",
|
||||
"type": "piechart"
|
||||
},
|
||||
{
|
||||
"cacheTimeout": null,
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"decimals": 0,
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 23
|
||||
},
|
||||
"id": 8,
|
||||
"interval": null,
|
||||
"links": [],
|
||||
"maxDataPoints": 3,
|
||||
"options": {
|
||||
"displayLabels": [],
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "table",
|
||||
"placement": "right",
|
||||
"values": [
|
||||
"value"
|
||||
]
|
||||
},
|
||||
"pieType": "pie",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"sum"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"text": {}
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "sum(rate(traefik_entrypoint_requests_total{entrypoint =~ \"$entrypoint\"}[5m])) by (entrypoint) ",
|
||||
"format": "time_series",
|
||||
"interval": "",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{ entrypoint }}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Requests by protocol",
|
||||
"type": "piechart"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 27,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"traefik",
|
||||
"prometheus"
|
||||
],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"allValue": null,
|
||||
"current": {},
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"definition": "label_values(service)",
|
||||
"description": null,
|
||||
"error": null,
|
||||
"hide": 0,
|
||||
"includeAll": false,
|
||||
"label": null,
|
||||
"multi": false,
|
||||
"name": "service",
|
||||
"options": [],
|
||||
"query": {
|
||||
"query": "label_values(service)",
|
||||
"refId": "StandardVariableQuery"
|
||||
},
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
"sort": 0,
|
||||
"tagValuesQuery": "",
|
||||
"tags": [],
|
||||
"tagsQuery": "",
|
||||
"type": "query",
|
||||
"useTags": false
|
||||
},
|
||||
{
|
||||
"allValue": null,
|
||||
"current": {},
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"definition": "",
|
||||
"description": null,
|
||||
"error": null,
|
||||
"hide": 0,
|
||||
"includeAll": true,
|
||||
"label": null,
|
||||
"multi": true,
|
||||
"name": "entrypoint",
|
||||
"options": [],
|
||||
"query": {
|
||||
"query": "label_values(entrypoint)",
|
||||
"refId": "Prometheus-entrypoint-Variable-Query"
|
||||
},
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
"sort": 0,
|
||||
"tagValuesQuery": "",
|
||||
"tags": [],
|
||||
"tagsQuery": "",
|
||||
"type": "query",
|
||||
"useTags": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"time_options": [
|
||||
"5m",
|
||||
"15m",
|
||||
"1h",
|
||||
"6h",
|
||||
"12h",
|
||||
"24h",
|
||||
"2d",
|
||||
"7d",
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Traefik",
|
||||
"uid": "qPdAviJmz",
|
||||
"version": 10
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
---
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
{{ with secret "kv/data/blocky" }}
|
||||
- name: Blocky logs
|
||||
url: {{ env "NOMAD_UPSTREAM_ADDR_mysql_server" }}
|
||||
database: {{ .Data.data.db_name }}
|
||||
type: mysql
|
||||
isDefault: false
|
||||
version: 1
|
||||
{{ with secret "kv/data/grafana" }}
|
||||
user: {{ .Data.data.db_user_ro }}
|
||||
secureJsonData:
|
||||
password: {{ .Data.data.db_pass_ro }}
|
||||
{{ end }}
|
||||
{{ end -}}
|
@ -1,50 +0,0 @@
|
||||
resource "nomad_job" "exporters" {
|
||||
hcl2 {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
jobspec = file("${path.module}/exporters.nomad")
|
||||
}
|
||||
|
||||
resource "nomad_job" "prometheus" {
|
||||
hcl2 {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
jobspec = file("${path.module}/prometheus.nomad")
|
||||
}
|
||||
|
||||
resource "nomad_job" "grafana" {
|
||||
hcl2 {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
jobspec = templatefile("${path.module}/grafana.nomad", {
|
||||
module_path = path.module
|
||||
})
|
||||
}
|
||||
|
||||
resource "consul_config_entry" "prometheus_intent" {
|
||||
name = "prometheus"
|
||||
kind = "service-intentions"
|
||||
|
||||
config_json = jsonencode({
|
||||
Sources = [
|
||||
{
|
||||
Action = "allow"
|
||||
Name = "grafana"
|
||||
Precedence = 9
|
||||
Type = "consul"
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
# resource "consul_config_entry" "envoy_prometheus_bind" {
|
||||
# name = "global"
|
||||
# kind = "proxy-defaults"
|
||||
#
|
||||
# config_json = jsonencode({
|
||||
# "envoy_prometheus_bind_addr" = "0.0.0.0:9102"
|
||||
# })
|
||||
# }
|
@ -1,168 +0,0 @@
|
||||
job "prometheus" {
|
||||
datacenters = ["dc1"]
|
||||
|
||||
group "prometheus" {
|
||||
count = 1
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
|
||||
port "web" {
|
||||
host_network = "loopback"
|
||||
to = 9090
|
||||
}
|
||||
}
|
||||
|
||||
ephemeral_disk {
|
||||
migrate = true
|
||||
sticky = true
|
||||
}
|
||||
|
||||
service {
|
||||
name = "prometheus"
|
||||
port = "web"
|
||||
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
local_service_port = 9090
|
||||
}
|
||||
}
|
||||
|
||||
sidecar_task {
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 50
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/"
|
||||
port = "web"
|
||||
interval = "10s"
|
||||
timeout = "10s"
|
||||
}
|
||||
|
||||
// TODO: Remove traefik tags
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.prometheus.entryPoints=websecure",
|
||||
]
|
||||
}
|
||||
|
||||
task "prometheus" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "prom/prometheus:v2.30.2"
|
||||
ports = ["web"]
|
||||
args = [
|
||||
"--config.file=/etc/prometheus/config/prometheus.yml",
|
||||
"--storage.tsdb.path=${NOMAD_ALLOC_DIR}/data/tsdb",
|
||||
"--web.listen-address=0.0.0.0:9090",
|
||||
"--web.console.libraries=/usr/share/prometheus/console_libraries",
|
||||
"--web.console.templates=/usr/share/prometheus/consoles",
|
||||
]
|
||||
|
||||
mount {
|
||||
type = "bind"
|
||||
target = "/etc/prometheus/config"
|
||||
source = "local/config"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
---
|
||||
global:
|
||||
scrape_interval: 30s
|
||||
evaluation_interval: 3s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: prometheus
|
||||
static_configs:
|
||||
- targets:
|
||||
- 0.0.0.0:9090
|
||||
|
||||
- job_name: "nomad_client"
|
||||
metrics_path: "/v1/metrics"
|
||||
params:
|
||||
format:
|
||||
- "prometheus"
|
||||
consul_sd_configs:
|
||||
- server: "http://{{env "attr.unique.network.ip-address"}}:8500"
|
||||
services:
|
||||
- "nomad-client"
|
||||
|
||||
- job_name: "consul"
|
||||
metrics_path: "/v1/agent/metrics"
|
||||
params:
|
||||
format:
|
||||
- "prometheus"
|
||||
consul_sd_configs:
|
||||
- server: "http://{{env "attr.unique.network.ip-address"}}:8500"
|
||||
services:
|
||||
- "consul"
|
||||
relabel_configs:
|
||||
- source_labels: [__meta_consul_address]
|
||||
replacement: $1:8500
|
||||
target_label: __address__
|
||||
|
||||
- job_name: "exporters"
|
||||
metrics_path: "/metrics"
|
||||
consul_sd_configs:
|
||||
- server: "http://{{env "attr.unique.network.ip-address"}}:8500"
|
||||
relabel_configs:
|
||||
- source_labels: [__meta_consul_service]
|
||||
action: drop
|
||||
regex: (.+)-sidecar-proxy
|
||||
- source_labels: [__meta_consul_service_metadata_metrics_addr]
|
||||
action: keep
|
||||
regex: (.+)
|
||||
- source_labels: [__meta_consul_service_metadata_metrics_addr]
|
||||
target_label: __address__
|
||||
- source_labels: [__meta_consul_service]
|
||||
target_label: consul_service
|
||||
- source_labels: [__meta_consul_node]
|
||||
target_label: consul_node
|
||||
- source_labels: [__meta_consul_service_nomad_dc]
|
||||
target_label: nomad_dc
|
||||
- source_labels: [__meta_consul_service_nomad_node_name]
|
||||
target_label: nomad_node_name
|
||||
|
||||
- job_name: "envoy"
|
||||
metrics_path: "/metrics"
|
||||
consul_sd_configs:
|
||||
- server: "http://{{env "attr.unique.network.ip-address"}}:8500"
|
||||
relabel_configs:
|
||||
- source_labels: [__meta_consul_service]
|
||||
action: keep
|
||||
regex: (.+)-sidecar-proxy
|
||||
- source_labels: [__meta_consul_service_metadata_envoy_metrics_addr]
|
||||
action: keep
|
||||
regex: (.+)
|
||||
- source_labels: [__meta_consul_service_metadata_envoy_metrics_addr]
|
||||
target_label: __address__
|
||||
- source_labels: [__meta_consul_service]
|
||||
target_label: consul_service
|
||||
- source_labels: [__meta_consul_node]
|
||||
target_label: consul_node
|
||||
- source_labels: [__meta_consul_service_nomad_dc]
|
||||
target_label: nomad_dc
|
||||
- source_labels: [__meta_consul_service_nomad_node_name]
|
||||
target_label: nomad_node_name
|
||||
EOF
|
||||
change_mode = "signal"
|
||||
change_signal = "SIGHUP"
|
||||
destination = "local/config/prometheus.yml"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 100
|
||||
memory = 300
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
32
core/nomad-client-stalker.nomad
Normal file
32
core/nomad-client-stalker.nomad
Normal file
@ -0,0 +1,32 @@
|
||||
job "nomad-client-stalker" {
|
||||
type = "system"
|
||||
|
||||
group "main" {
|
||||
|
||||
network {
|
||||
mode = "host"
|
||||
port "main" {}
|
||||
}
|
||||
|
||||
service {
|
||||
name = "nomad-client-stalker"
|
||||
provider = "nomad"
|
||||
port = "main"
|
||||
}
|
||||
|
||||
task "main" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "busybox"
|
||||
args = ["tail", "-f", "/dev/null"]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 10
|
||||
memory = 15
|
||||
memory_max = 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
40
core/oidc_client/.terraform.lock.hcl
Normal file
40
core/oidc_client/.terraform.lock.hcl
Normal file
@ -0,0 +1,40 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "2.3.1"
|
||||
hashes = [
|
||||
"h1:lMueBNB2GJ/a5rweL9NPybwVfDH/Q1s+rQvt5Y+kuYs=",
|
||||
"zh:1e7893a3fbebff171bcc5581b70a16eea33193c7e9dd73402ba5c04b7202f0bb",
|
||||
"zh:252cfd3fee4811c83bc74406ba1bc1bbb83d6de20e50a86f93737f8f86864171",
|
||||
"zh:387a7140be6dfa3f8d27f09d1eb2b9f3b84900328fe5a0478e9b3bd91a845808",
|
||||
"zh:49848fa491ac26b0568b112a57d14cc49772607c7cf405e2f74dd537407214b1",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:7b9f345f5bb5f17c5d0bc3d373c25828934a3cbcdb331e0eab54eb47f1355fb2",
|
||||
"zh:8e276f4de508a86e725fffc02ee891db73397c35dbd591d8918af427eeec93a1",
|
||||
"zh:90b349933d2fd28f822a36128be4625bb816aa9f20ec314c79c77306f632ae87",
|
||||
"zh:a0ca6fd6cd94a52684e432104d3dc170a74075f47d9d4ba725cc340a438ed75a",
|
||||
"zh:a6cffc45535a0ff8206782538b3eeaef17dc93d0e1fd58bc1e6f7d5aa0f6ba1a",
|
||||
"zh:c010807b5d3e03d769419787b0e5d4efa6963134e1873a413102af6bf3dd1c49",
|
||||
"zh:faf962ee1981e897e99f7e528642c7e74beed37afd8eaf743e6ede24df812d80",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.6.2"
|
||||
hashes = [
|
||||
"h1:wmG0QFjQ2OfyPy6BB7mQ57WtoZZGGV07uAPQeDmIrAE=",
|
||||
"zh:0ef01a4f81147b32c1bea3429974d4d104bbc4be2ba3cfa667031a8183ef88ec",
|
||||
"zh:1bcd2d8161e89e39886119965ef0f37fcce2da9c1aca34263dd3002ba05fcb53",
|
||||
"zh:37c75d15e9514556a5f4ed02e1548aaa95c0ecd6ff9af1119ac905144c70c114",
|
||||
"zh:4210550a767226976bc7e57d988b9ce48f4411fa8a60cd74a6b246baf7589dad",
|
||||
"zh:562007382520cd4baa7320f35e1370ffe84e46ed4e2071fdc7e4b1a9b1f8ae9b",
|
||||
"zh:5efb9da90f665e43f22c2e13e0ce48e86cae2d960aaf1abf721b497f32025916",
|
||||
"zh:6f71257a6b1218d02a573fc9bff0657410404fb2ef23bc66ae8cd968f98d5ff6",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:9647e18f221380a85f2f0ab387c68fdafd58af6193a932417299cdcae4710150",
|
||||
"zh:bb6297ce412c3c2fa9fec726114e5e0508dd2638cad6a0cb433194930c97a544",
|
||||
"zh:f83e925ed73ff8a5ef6e3608ad9225baa5376446349572c2449c0c0b3cf184b7",
|
||||
"zh:fbef0781cb64de76b1df1ca11078aecba7800d82fd4a956302734999cfd9a4af",
|
||||
]
|
||||
}
|
50
core/oidc_client/main.tf
Normal file
50
core/oidc_client/main.tf
Normal file
@ -0,0 +1,50 @@
|
||||
resource "random_password" "oidc_client_id" {
|
||||
length = 72
|
||||
override_special = "-._~"
|
||||
}
|
||||
|
||||
resource "random_password" "oidc_secret" {
|
||||
length = 72
|
||||
override_special = "-._~"
|
||||
}
|
||||
|
||||
resource "nomad_variable" "authelia_oidc_secret" {
|
||||
path = "secrets/authelia/${var.name}"
|
||||
items = {
|
||||
client_id = resource.random_password.oidc_client_id.result
|
||||
secret = resource.random_password.oidc_secret.result
|
||||
secret_hash = resource.random_password.oidc_secret.bcrypt_hash
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_variable" "authelia_access_control_oidc" {
|
||||
path = "authelia/access_control/oidc_clients/${var.name}"
|
||||
items = {
|
||||
id = resource.random_password.oidc_client_id.result
|
||||
description = var.oidc_client_config.description
|
||||
authorization_policy = var.oidc_client_config.authorization_policy
|
||||
redirect_uris = yamlencode(var.oidc_client_config.redirect_uris)
|
||||
scopes = yamlencode(var.oidc_client_config.scopes)
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "oidc_authelia" {
|
||||
count = var.job_acl != null ? 1 : 0
|
||||
name = "${var.name}-authelia"
|
||||
description = "Give access to shared authelia variables"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/authelia/${var.name}" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
job_id = var.job_acl.job_id
|
||||
group = var.job_acl.group
|
||||
task = var.job_acl.task
|
||||
}
|
||||
}
|
11
core/oidc_client/output.tf
Normal file
11
core/oidc_client/output.tf
Normal file
@ -0,0 +1,11 @@
|
||||
output "client_id" {
|
||||
value = resource.random_password.oidc_client_id.result
|
||||
}
|
||||
|
||||
output "secret" {
|
||||
value = resource.random_password.oidc_secret.result
|
||||
}
|
||||
|
||||
output "secret_hash" {
|
||||
value = resource.random_password.oidc_secret.bcrypt_hash
|
||||
}
|
25
core/oidc_client/vars.tf
Normal file
25
core/oidc_client/vars.tf
Normal file
@ -0,0 +1,25 @@
|
||||
variable "name" {
|
||||
description = "Name of service"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "oidc_client_config" {
|
||||
description = "Authelia oidc client configuration to enable oidc authentication"
|
||||
type = object({
|
||||
description = string
|
||||
authorization_policy = optional(string, "one_factor")
|
||||
redirect_uris = list(string)
|
||||
scopes = list(string)
|
||||
})
|
||||
}
|
||||
|
||||
variable "job_acl" {
|
||||
description = "Job ACL that should be given to the secrets"
|
||||
type = object({
|
||||
job_id = string
|
||||
group = optional(string)
|
||||
task = optional(string)
|
||||
})
|
||||
|
||||
default = null
|
||||
}
|
169
core/prometheus.nomad
Normal file
169
core/prometheus.nomad
Normal file
@ -0,0 +1,169 @@
|
||||
job "prometheus" {
|
||||
datacenters = ["dc1"]
|
||||
|
||||
group "prometheus" {
|
||||
count = 1
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
|
||||
port "web" {
|
||||
%{~ if use_wesher ~}
|
||||
host_network = "wesher"
|
||||
%{~ endif ~}
|
||||
to = 9090
|
||||
}
|
||||
|
||||
port "pushgateway" {
|
||||
%{~ if use_wesher ~}
|
||||
host_network = "wesher"
|
||||
%{~ endif ~}
|
||||
static = 9091
|
||||
}
|
||||
}
|
||||
|
||||
ephemeral_disk {
|
||||
migrate = true
|
||||
sticky = true
|
||||
}
|
||||
|
||||
service {
|
||||
name = "prometheus"
|
||||
provider = "nomad"
|
||||
port = "web"
|
||||
|
||||
// TODO: Remove traefik tags
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.prometheus.entryPoints=websecure",
|
||||
]
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/-/healthy"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
|
||||
check_restart {
|
||||
limit = 3
|
||||
grace = "5m"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
service {
|
||||
name = "pushgateway"
|
||||
provider = "nomad"
|
||||
port = "pushgateway"
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/-/healthy"
|
||||
interval = "10s"
|
||||
timeout = "3s"
|
||||
|
||||
check_restart {
|
||||
limit = 3
|
||||
grace = "5m"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task "prometheus" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "prom/prometheus:v2.43.0"
|
||||
ports = ["web"]
|
||||
args = [
|
||||
"--config.file=$${NOMAD_TASK_DIR}/prometheus.yml",
|
||||
"--storage.tsdb.path=$${NOMAD_ALLOC_DIR}/data/tsdb",
|
||||
"--web.listen-address=0.0.0.0:9090",
|
||||
"--web.console.libraries=/usr/share/prometheus/console_libraries",
|
||||
"--web.console.templates=/usr/share/prometheus/consoles",
|
||||
]
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
---
|
||||
global:
|
||||
scrape_interval: 30s
|
||||
evaluation_interval: 3s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: prometheus
|
||||
static_configs:
|
||||
- targets:
|
||||
- 127.0.0.1:9090
|
||||
|
||||
- job_name: "pushgateway"
|
||||
honor_labels: true
|
||||
static_configs:
|
||||
- targets:
|
||||
- 127.0.0.1:9091
|
||||
|
||||
- job_name: "nomad_client"
|
||||
metrics_path: "/v1/metrics"
|
||||
params:
|
||||
format:
|
||||
- "prometheus"
|
||||
nomad_sd_configs:
|
||||
# TODO: Use NOMAD_SECRETS_DIR/api.sock and workload idenity when
|
||||
# workload acls can be set using terraform
|
||||
- server: "http://{{env "attr.unique.network.ip-address"}}:4646"
|
||||
relabel_configs:
|
||||
- source_labels: [__meta_nomad_service]
|
||||
regex: nomad-client-stalker
|
||||
action: keep
|
||||
- source_labels: [__meta_nomad_address]
|
||||
replacement: "$1:4646"
|
||||
target_label: __address__
|
||||
|
||||
- job_name: "nomad_services"
|
||||
metrics_path: "/metrics"
|
||||
nomad_sd_configs:
|
||||
- server: "http://{{env "attr.unique.network.ip-address"}}:4646"
|
||||
relabel_configs:
|
||||
- source_labels: [__meta_nomad_tags]
|
||||
regex: .*(prometheus.scrape).*
|
||||
action: keep
|
||||
- source_labels: [__meta_nomad_service_address,__meta_nomad_service_port]
|
||||
separator: ":"
|
||||
target_label: __address__
|
||||
- source_labels: [__meta_nomad_service]
|
||||
target_label: nomad_service
|
||||
- source_labels: [__meta_nomad_dc]
|
||||
target_label: nomad_dc
|
||||
- source_labels: [__meta_nomad_node_id]
|
||||
target_label: nomad_node_id
|
||||
EOF
|
||||
change_mode = "signal"
|
||||
change_signal = "SIGHUP"
|
||||
destination = "$${NOMAD_TASK_DIR}/prometheus.yml"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 100
|
||||
memory = 300
|
||||
}
|
||||
}
|
||||
|
||||
task "pushgateway" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "prom/pushgateway"
|
||||
ports = ["pushgateway"]
|
||||
args = [
|
||||
"--persistence.file=$${NOMAD_ALLOC_DIR}/pushgateway-persistence",
|
||||
]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,35 +19,19 @@ job "syslogng" {
|
||||
|
||||
service {
|
||||
name = "syslogng-promtail"
|
||||
provider = "nomad"
|
||||
port = "main"
|
||||
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
local_service_port = 1514
|
||||
|
||||
upstreams {
|
||||
destination_name = "loki"
|
||||
local_bind_port = 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sidecar_task {
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 20
|
||||
memory_max = 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task "promtail" {
|
||||
driver = "docker"
|
||||
|
||||
meta = {
|
||||
"diun.watch_repo" = true
|
||||
}
|
||||
|
||||
config {
|
||||
image = "grafana/promtail:2.2.1"
|
||||
image = "grafana/promtail:2.9.1"
|
||||
ports = ["main", "metrics"]
|
||||
args = ["--config.file=/etc/promtail/promtail.yml"]
|
||||
|
||||
@ -66,7 +50,9 @@ server:
|
||||
http_listen_port: 9080
|
||||
|
||||
clients:
|
||||
- url: http://{{ env "NOMAD_UPSTREAM_ADDR_loki" }}/loki/api/v1/push
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "loki" -}}
|
||||
- url: http://{{ .Address }}:{{ .Port }}/loki/api/v1/push
|
||||
{{- end }}
|
||||
|
||||
scrape_configs:
|
||||
# TCP syslog receiver
|
||||
@ -84,7 +70,7 @@ EOF
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 20
|
||||
memory = 50
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -101,28 +87,8 @@ EOF
|
||||
|
||||
service {
|
||||
name = "syslogng"
|
||||
provider = "nomad"
|
||||
port = "main"
|
||||
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
local_service_port = 514
|
||||
|
||||
upstreams {
|
||||
destination_name = "syslogng-promtail"
|
||||
local_bind_port = 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sidecar_task {
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 20
|
||||
memory_max = 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task "syslogng" {
|
||||
@ -155,8 +121,9 @@ source s_internal {
|
||||
};
|
||||
|
||||
destination d_loki {
|
||||
# Forward to Connect proxy to Promtail
|
||||
syslog("{{ env "NOMAD_UPSTREAM_IP_syslogng-promtail" }}" transport("tcp") port({{ env "NOMAD_UPSTREAM_PORT_syslogng-promtail" }}));
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "syslogng-promtail" -}}
|
||||
syslog("{{ .Address }}" transport("tcp") port({{ .Port }}));
|
||||
{{- end }}
|
||||
};
|
||||
|
||||
log { source(s_internal); destination(d_loki); };
|
||||
@ -167,7 +134,7 @@ EOF
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 10
|
||||
memory = 50
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,20 @@
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "1.4.17"
|
||||
version = "2.1.0"
|
||||
hashes = [
|
||||
"h1:iPylWr144mqXvM8NBVMTm+MS6JRhqIihlpJG91GYDyA=",
|
||||
"zh:146f97eacd9a0c78b357a6cfd2cb12765d4b18e9660a75500ee3e748c6eba41a",
|
||||
"zh:2eb89a6e5cee9aea03a96ea9f141096fe3baf219b2700ce30229d2d882f5015f",
|
||||
"zh:3d0f971f79b615c1014c75e2f99f34bd4b4da542ca9f31d5ea7fadc4e9de39c1",
|
||||
"zh:46099a750c752ce05aa14d663a86478a5ad66d95aff3d69367f1d3628aac7792",
|
||||
"zh:71e56006b013dcfe1e4e059b2b07148b44fcd79351ae2c357e0d97e27ae0d916",
|
||||
"zh:74febd25d776688f0558178c2f5a0e6818bbf4cdaa2e160d7049da04103940f0",
|
||||
"h1:ek0L7fA+4R1/BXhbutSRqlQPzSZ5aY/I2YfVehuYeEU=",
|
||||
"zh:39ba4d4fc9557d4d2c1e4bf866cf63973359b73e908cce237c54384512bdb454",
|
||||
"zh:40d2b66e3f3675e6b88000c145977c1d5288510c76b702c6c131d9168546c605",
|
||||
"zh:40fbe575d85a083f96d4703c6b7334e9fc3e08e4f1d441de2b9513215184ebcc",
|
||||
"zh:42ce6db79e2f94557fae516ee3f22e5271f0b556638eb45d5fbad02c99fc7af3",
|
||||
"zh:4acf63dfb92f879b3767529e75764fef68886521b7effa13dd0323c38133ce88",
|
||||
"zh:72cf35a13c2fb542cd3c8528826e2390db9b8f6f79ccb41532e009ad140a3269",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:af18c064a5f0dd5422d6771939274841f635b619ab392c73d5bf9720945fdb85",
|
||||
"zh:c133d7a862079da9f06e301c530eacbd70e9288fa2276ec0704df907270ee328",
|
||||
"zh:c894cf98d239b9f5a4b7cde9f5c836face0b5b93099048ee817b0380ea439c65",
|
||||
"zh:c918642870f0cafdbe4d7dd07c909701fc3ddb47cac8357bdcde1327bf78c11d",
|
||||
"zh:f8f5655099a57b4b9c0018a2d49133771e24c7ff8262efb1ceb140fd224aa9b6",
|
||||
"zh:8b8bcc136c05916234cb0c3bcc3d48fda7ca551a091ad8461ea4ab16fb6960a3",
|
||||
"zh:8e1c2f924eae88afe7ac83775f000ae8fd71a04e06228edf7eddce4df2421169",
|
||||
"zh:abc6e725531fc06a8e02e84946aaabc3453ecafbc1b7a442ea175db14fd9c86a",
|
||||
"zh:b735fcd1fb20971df3e92f81bb6d73eef845dcc9d3d98e908faa3f40013f0f69",
|
||||
"zh:ce59797282505d872903789db8f092861036da6ec3e73f6507dac725458a5ec9",
|
||||
]
|
||||
}
|
||||
|
@ -1,9 +1,3 @@
|
||||
variable "base_hostname" {
|
||||
type = string
|
||||
description = "Base hostname to serve content from"
|
||||
default = "dev.homelab"
|
||||
}
|
||||
|
||||
job "traefik" {
|
||||
datacenters = ["dc1"]
|
||||
type = "service"
|
||||
@ -20,13 +14,15 @@ job "traefik" {
|
||||
|
||||
update {
|
||||
max_parallel = 1
|
||||
# canary = 1
|
||||
# auto_promote = true
|
||||
canary = 1
|
||||
auto_promote = false
|
||||
auto_revert = true
|
||||
min_healthy_time = "30s"
|
||||
healthy_deadline = "5m"
|
||||
}
|
||||
|
||||
group "traefik" {
|
||||
count = 1
|
||||
count = 2
|
||||
|
||||
network {
|
||||
port "web" {
|
||||
@ -40,6 +36,20 @@ job "traefik" {
|
||||
port "syslog" {
|
||||
static = 514
|
||||
}
|
||||
|
||||
port "gitssh" {
|
||||
static = 2222
|
||||
}
|
||||
|
||||
port "metrics" {}
|
||||
|
||||
dns {
|
||||
servers = [
|
||||
"192.168.2.101",
|
||||
"192.168.2.102",
|
||||
"192.168.2.30",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
ephemeral_disk {
|
||||
@ -47,36 +57,42 @@ job "traefik" {
|
||||
sticky = true
|
||||
}
|
||||
|
||||
service {
|
||||
name = "traefik"
|
||||
port = "web"
|
||||
|
||||
check {
|
||||
type = "http"
|
||||
path = "/ping"
|
||||
port = "web"
|
||||
interval = "10s"
|
||||
timeout = "2s"
|
||||
}
|
||||
|
||||
connect {
|
||||
native = true
|
||||
}
|
||||
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.traefik.entryPoints=websecure",
|
||||
"traefik.http.routers.traefik.service=api@internal",
|
||||
]
|
||||
}
|
||||
|
||||
task "traefik" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "traefik:2.9"
|
||||
service {
|
||||
name = "traefik"
|
||||
provider = "nomad"
|
||||
port = "web"
|
||||
|
||||
ports = ["web", "websecure"]
|
||||
check {
|
||||
type = "http"
|
||||
path = "/ping"
|
||||
interval = "10s"
|
||||
timeout = "2s"
|
||||
}
|
||||
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.traefik.entryPoints=websecure",
|
||||
"traefik.http.routers.traefik.service=api@internal",
|
||||
]
|
||||
}
|
||||
|
||||
service {
|
||||
name = "traefik-metrics"
|
||||
provider = "nomad"
|
||||
port = "metrics"
|
||||
|
||||
tags = [
|
||||
"prometheus.scrape",
|
||||
]
|
||||
}
|
||||
|
||||
config {
|
||||
image = "traefik:3.0"
|
||||
|
||||
ports = ["web", "websecure", "syslog", "gitssh", "metrics"]
|
||||
network_mode = "host"
|
||||
|
||||
mount {
|
||||
@ -90,10 +106,20 @@ job "traefik" {
|
||||
target = "/etc/traefik/usersfile"
|
||||
source = "secrets/usersfile"
|
||||
}
|
||||
|
||||
mount {
|
||||
type = "bind"
|
||||
target = "/etc/traefik/certs"
|
||||
source = "secrets/certs"
|
||||
}
|
||||
}
|
||||
|
||||
vault {
|
||||
policies = ["access-tables", "nomad-task"]
|
||||
env = {
|
||||
TRAEFIK_PROVIDERS_NOMAD_ENDPOINT_TOKEN = "${NOMAD_TOKEN}"
|
||||
}
|
||||
|
||||
identity {
|
||||
env = true
|
||||
}
|
||||
|
||||
template {
|
||||
@ -116,14 +142,9 @@ job "traefik" {
|
||||
[entryPoints.websecure]
|
||||
address = ":443"
|
||||
[entryPoints.websecure.http.tls]
|
||||
<< if keyExists "traefik/acme/email" ->>
|
||||
certResolver = "letsEncrypt"
|
||||
[[entryPoints.websecure.http.tls.domains]]
|
||||
main = "*.<< keyOrDefault "global/base_hostname" "${var.base_hostname}" >>"
|
||||
<< end ->>
|
||||
|
||||
[entryPoints.metrics]
|
||||
address = ":8989"
|
||||
address = ":<< env "NOMAD_PORT_metrics" >>"
|
||||
|
||||
[entryPoints.syslogtcp]
|
||||
address = ":514"
|
||||
@ -131,6 +152,9 @@ job "traefik" {
|
||||
[entryPoints.syslogudp]
|
||||
address = ":514/udp"
|
||||
|
||||
[entryPoints.gitssh]
|
||||
address = ":2222"
|
||||
|
||||
[api]
|
||||
dashboard = true
|
||||
|
||||
@ -146,37 +170,13 @@ job "traefik" {
|
||||
directory = "/etc/traefik/conf"
|
||||
watch = true
|
||||
|
||||
[providers.consulCatalog]
|
||||
connectAware = true
|
||||
connectByDefault = true
|
||||
[providers.nomad]
|
||||
exposedByDefault = false
|
||||
defaultRule = "Host(`{{normalize .Name}}.<< keyOrDefault "global/base_hostname" "${var.base_hostname}" >>`)"
|
||||
[providers.consulCatalog.endpoint]
|
||||
address = "http://<< env "CONSUL_HTTP_ADDR" >>"
|
||||
|
||||
<< if keyExists "traefik/acme/email" ->>
|
||||
[certificatesResolvers.letsEncrypt.acme]
|
||||
email = "<< key "traefik/acme/email" >>"
|
||||
# Store in /local because /secrets doesn't persist with ephemeral disk
|
||||
storage = "/local/acme.json"
|
||||
[certificatesResolvers.letsEncrypt.acme.dnsChallenge]
|
||||
provider = "cloudflare"
|
||||
resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
|
||||
delayBeforeCheck = 0
|
||||
<< end ->>
|
||||
defaultRule = "Host(`{{normalize .Name}}.<< with nomadVar "nomad/jobs" >><< .base_hostname >><< end >>`)"
|
||||
[providers.nomad.endpoint]
|
||||
address = "unix:///secrets/api.sock"
|
||||
EOH
|
||||
destination = "local/config/traefik.toml"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
{{ with secret "kv/data/cloudflare" }}
|
||||
CF_DNS_API_TOKEN={{ .Data.data.domain_lego_dns }}
|
||||
CF_ZONE_API_TOKEN={{ .Data.data.domain_lego_dns }}
|
||||
{{ end }}
|
||||
EOH
|
||||
destination = "secrets/cloudflare.env"
|
||||
env = true
|
||||
destination = "${NOMAD_TASK_DIR}/config/traefik.toml"
|
||||
}
|
||||
|
||||
template {
|
||||
@ -185,55 +185,55 @@ CF_ZONE_API_TOKEN={{ .Data.data.domain_lego_dns }}
|
||||
[http.routers]
|
||||
[http.routers.nomad]
|
||||
entryPoints = ["websecure"]
|
||||
# middlewares = []
|
||||
service = "nomad"
|
||||
rule = "Host(`nomad.{{ keyOrDefault "global/base_hostname" "${var.base_hostname}" }}`)"
|
||||
[http.routers.consul]
|
||||
rule = "Host(`nomad.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}`)"
|
||||
|
||||
{{ range nomadVarList "traefik_external" }}{{ with nomadVar .Path }}
|
||||
[http.routers.{{ .name }}]
|
||||
entryPoints = ["websecure"]
|
||||
# middlewares = []
|
||||
service = "consul"
|
||||
rule = "Host(`consul.{{ keyOrDefault "global/base_hostname" "${var.base_hostname}" }}`)"
|
||||
[http.routers.vault]
|
||||
entryPoints = ["websecure"]
|
||||
# middlewares = []
|
||||
service = "vault"
|
||||
rule = "Host(`vault.{{ keyOrDefault "global/base_hostname" "${var.base_hostname}" }}`)"
|
||||
service = "{{ .name }}"
|
||||
rule = "Host(`{{ .subdomain }}.{{ with nomadVar "nomad/jobs" }}{{ .base_hostname }}{{ end }}`){{ with .path_prefix.Value }}&&PathPrefix(`{{ . }}`){{ end }}"
|
||||
{{ $name := .name -}}
|
||||
{{ with .path_prefix.Value -}}
|
||||
middlewares = ["{{ $name }}@file"]
|
||||
{{ end }}
|
||||
{{- end }}{{ end }}
|
||||
|
||||
#[http.middlewares]
|
||||
# {{ range nomadVarList "traefik_external" }}{{ with nomadVar .Path -}}
|
||||
# {{ $name := .name -}}
|
||||
# {{ with .path_prefix.Value -}}
|
||||
# [http.middlewares.{{ $name }}.stripPrefix]
|
||||
# prefixes = ["{{ . }}"]
|
||||
# {{ end }}
|
||||
# {{- end }}{{ end }}
|
||||
|
||||
[http.services]
|
||||
{{ with service "nomad-client" -}}
|
||||
[http.services.nomad]
|
||||
[http.services.nomad.loadBalancer]
|
||||
{{ range . -}}
|
||||
[[http.services.nomad.loadBalancer.servers]]
|
||||
url = "http://{{ .Address }}:{{ .Port }}"
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
{{ with service "consul" -}}
|
||||
[http.services.consul]
|
||||
[http.services.consul.loadBalancer]
|
||||
{{ range . -}}
|
||||
[[http.services.consul.loadBalancer.servers]]
|
||||
# Not using .Port because that's an RPC port
|
||||
url = "http://{{ .Address }}:8500"
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
{{ with service "vault" -}}
|
||||
[http.services.vault]
|
||||
[http.services.vault.loadBalancer]
|
||||
[http.services.vault.loadBalancer.sticky.cookie]
|
||||
{{ range . -}}
|
||||
[[http.services.vault.loadBalancer.servers]]
|
||||
url = "http://{{ .Address }}:{{ .Port }}"
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
url = "http://127.0.0.1:4646"
|
||||
|
||||
{{ range nomadVarList "traefik_external" }}{{ with nomadVar .Path }}
|
||||
[http.services.{{ .name }}]
|
||||
[http.services.{{ .name }}.loadBalancer]
|
||||
[[http.services.{{ .name }}.loadBalancer.servers]]
|
||||
url = "{{ .url }}"
|
||||
{{- end }}{{ end }}
|
||||
EOH
|
||||
destination = "local/config/conf/route-hashi.toml"
|
||||
destination = "${NOMAD_TASK_DIR}/config/conf/route-hashi.toml"
|
||||
change_mode = "noop"
|
||||
splay = "1m"
|
||||
|
||||
wait {
|
||||
min = "10s"
|
||||
max = "20s"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
{{ with service "syslogng" -}}
|
||||
{{ with nomadService "syslogng" -}}
|
||||
[tcp.routers]
|
||||
[tcp.routers.syslogtcp]
|
||||
entryPoints = ["syslogtcp"]
|
||||
@ -247,9 +247,9 @@ CF_ZONE_API_TOKEN={{ .Data.data.domain_lego_dns }}
|
||||
[[tcp.services.syslogngtcp.loadBalancer.servers]]
|
||||
address = "{{ .Address }}:{{ .Port }}"
|
||||
{{ end -}}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
|
||||
{{ with service "syslogng" -}}
|
||||
{{ with nomadService "syslogng" -}}
|
||||
[udp.routers]
|
||||
[udp.routers.syslogudp]
|
||||
entryPoints = ["syslogudp"]
|
||||
@ -262,40 +262,71 @@ CF_ZONE_API_TOKEN={{ .Data.data.domain_lego_dns }}
|
||||
[[udp.services.syslogngudp.loadBalancer.servers]]
|
||||
address = "{{ .Address }}:{{ .Port }}"
|
||||
{{ end -}}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
EOH
|
||||
destination = "local/config/conf/route-syslog-ng.toml"
|
||||
destination = "${NOMAD_TASK_DIR}/config/conf/route-syslog-ng.toml"
|
||||
change_mode = "noop"
|
||||
splay = "1m"
|
||||
|
||||
wait {
|
||||
min = "10s"
|
||||
max = "20s"
|
||||
}
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{- with nomadVar "secrets/certs/_lego/certificates/__thefij_rocks_crt" }}{{ .contents }}{{ end -}}"
|
||||
EOF
|
||||
destination = "${NOMAD_SECRETS_DIR}/certs/_.thefij.rocks.crt"
|
||||
change_mode = "noop"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{- with nomadVar "secrets/certs/_lego/certificates/__thefij_rocks_key" }}{{ .contents }}{{ end -}}"
|
||||
EOF
|
||||
destination = "${NOMAD_SECRETS_DIR}/certs/_.thefij.rocks.key"
|
||||
change_mode = "noop"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
[[tls.certificates]]
|
||||
certFile = "/etc/traefik/certs/_.thefij.rocks.crt"
|
||||
keyFile = "/etc/traefik/certs/_.thefij.rocks.key"
|
||||
EOH
|
||||
destination = "${NOMAD_TASK_DIR}/config/conf/dynamic-tls.toml"
|
||||
change_mode = "noop"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
[http.middlewares]
|
||||
{{ with secret "kv/data/traefik" }}
|
||||
{{ if .Data.data.usersfile }}
|
||||
{{ with nomadVar "nomad/jobs/traefik" }}
|
||||
{{ if .usersfile }}
|
||||
[http.middlewares.basic-auth.basicAuth]
|
||||
usersFile = "/etc/traefik/usersfile"
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
EOH
|
||||
destination = "local/config/conf/middlewares.toml"
|
||||
destination = "${NOMAD_TASK_DIR}/config/conf/middlewares.toml"
|
||||
change_mode = "noop"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
{{ with secret "kv/data/traefik" }}
|
||||
{{ .Data.data.usersfile }}
|
||||
{{ end }}
|
||||
{{ with nomadVar "nomad/jobs/traefik" -}}
|
||||
{{ .usersfile }}
|
||||
{{- end }}
|
||||
EOH
|
||||
destination = "secrets/usersfile"
|
||||
destination = "${NOMAD_SECRETS_DIR}/usersfile"
|
||||
change_mode = "noop"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 100
|
||||
memory = 100
|
||||
memory_max = 500
|
||||
memory = 150
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,81 @@
|
||||
variable "base_hostname" {
|
||||
type = string
|
||||
description = "Base hostname to serve content from"
|
||||
default = "dev.homelab"
|
||||
}
|
||||
|
||||
resource "nomad_job" "traefik" {
|
||||
hcl2 {
|
||||
enabled = true
|
||||
vars = {
|
||||
"base_hostname" = var.base_hostname,
|
||||
}
|
||||
}
|
||||
|
||||
jobspec = file("${path.module}/traefik.nomad")
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "treafik_secrets_certs_read" {
|
||||
name = "traefik-secrets-certs-read"
|
||||
description = "Read certs to secrets store"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/certs/*" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
path "secrets/certs" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
job_acl {
|
||||
job_id = resource.nomad_job.traefik.id
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "traefik_query_jobs" {
|
||||
name = "traefik-query-jobs"
|
||||
description = "Allow traefik to query jobs"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
capabilities = ["list-jobs", "read-job"]
|
||||
}
|
||||
EOH
|
||||
job_acl {
|
||||
job_id = resource.nomad_job.traefik.id
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "treafik_external" {
|
||||
name = "traefik-exernal"
|
||||
description = "Read external services"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "traefik_external/*" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
job_acl {
|
||||
job_id = "traefik"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_variable" "traefik_external_hass" {
|
||||
path = "traefik_external/hass"
|
||||
items = {
|
||||
name = "hass"
|
||||
subdomain = "hass",
|
||||
url = "http://192.168.3.65:8123"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_variable" "traefik_external_plex" {
|
||||
path = "traefik_external/plex"
|
||||
items = {
|
||||
name = "plex"
|
||||
subdomain = "plex",
|
||||
url = "http://agnosticfront.thefij:32400"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_variable" "traefik_external_appdaemon" {
|
||||
path = "traefik_external/appdaemon"
|
||||
items = {
|
||||
name = "appdaemon"
|
||||
subdomain = "appdash",
|
||||
url = "http://192.168.3.65:5050"
|
||||
# path_prefix = "/add"
|
||||
}
|
||||
}
|
||||
|
@ -3,3 +3,9 @@ variable "base_hostname" {
|
||||
description = "Base hostname to serve content from"
|
||||
default = "dev.homelab"
|
||||
}
|
||||
|
||||
variable "use_wesher" {
|
||||
type = bool
|
||||
description = "Indicates whether or not services should expose themselves on the wesher network"
|
||||
default = true
|
||||
}
|
||||
|
@ -1,40 +1,40 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/consul" {
|
||||
version = "2.15.1"
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "2.0.0"
|
||||
hashes = [
|
||||
"h1:PexyQBRLDA+SR+sWlzYBZswry5O5h/tTfj87CaECtLc=",
|
||||
"zh:1806830a3cf103e65e772a7d28fd4df2788c29a029fb2def1326bc777ad107ed",
|
||||
"zh:252be544fb4c9daf09cad7d3776daf5fa66b62740d3ea9d6d499a7b1697c3433",
|
||||
"zh:50985fe02a8e5ae47c75d7c28c911b25d7dc4716cff2ed55ca05889ab77a1f73",
|
||||
"zh:54cf0ec90538703c66937c77e8d72a38d5af47437eb0b8b55eb5836c5d288878",
|
||||
"zh:704f536c621337e06fffef6d5f49ac81f52d249f937250527c12884cb83aefed",
|
||||
"zh:896d8ef6d0b555299f124eb25bce8a17d735da14ef21f07582098d301f47da30",
|
||||
"zh:976277a85b0a0baafe267cc494f766448d1da5b6936ddcb3ce393bd4d22f08d2",
|
||||
"zh:c7faa9a2b11bc45833a3e8e340f22f1ecf01597eaeffa7669234b4549d7dfa85",
|
||||
"zh:caf851ef9c8ce482864badf7058f9278d4537112fa236efd8f1a9315801d9061",
|
||||
"zh:db203435d58b0ac842540861b3307a623423275d85754c171773f3b210ae5b24",
|
||||
"zh:f3d3efac504c9484a025beb919d22b290aa6dbff256f6e86c1f8ce7817e077e5",
|
||||
"zh:f710a37190429045d109edd35de69db3b5f619919c2fa04c77a3a639fea9fd7d",
|
||||
"h1:lIHIxA6ZmfyTGL3J9YIddhxlfit4ipSS09BLxkwo6L0=",
|
||||
"zh:09b897d64db293f9a904a4a0849b11ec1e3fff5c638f734d82ae36d8dc044b72",
|
||||
"zh:435cc106799290f64078ec24b6c59cb32b33784d609088638ed32c6d12121199",
|
||||
"zh:7073444bd064e8c4ec115ca7d9d7f030cc56795c0a83c27f6668bba519e6849a",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:79d238c35d650d2d83a439716182da63f3b2767e72e4cbd0b69cb13d9b1aebfc",
|
||||
"zh:7ef5f49344278fe0bbc5447424e6aa5425ff1821d010d944a444d7fa2c751acf",
|
||||
"zh:92179091638c8ba03feef371c4361a790190f9955caea1fa59de2055c701a251",
|
||||
"zh:a8a34398851761368eb8e7c171f24e55efa6e9fdbb5c455f6dec34dc17f631bc",
|
||||
"zh:b38fd5338625ebace5a4a94cea1a28b11bd91995d834e318f47587cfaf6ec599",
|
||||
"zh:b71b273a2aca7ad5f1e07c767b25b5a888881ba9ca93b30044ccc39c2937f03c",
|
||||
"zh:cd14357e520e0f09fb25badfb4f2ee37d7741afdc3ed47c7bcf54c1683772543",
|
||||
"zh:e05e025f4bb95138c3c8a75c636e97cd7cfd2fc1525b0c8bd097db8c5f02df6e",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/nomad" {
|
||||
version = "1.4.17"
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.5.1"
|
||||
hashes = [
|
||||
"h1:iPylWr144mqXvM8NBVMTm+MS6JRhqIihlpJG91GYDyA=",
|
||||
"zh:146f97eacd9a0c78b357a6cfd2cb12765d4b18e9660a75500ee3e748c6eba41a",
|
||||
"zh:2eb89a6e5cee9aea03a96ea9f141096fe3baf219b2700ce30229d2d882f5015f",
|
||||
"zh:3d0f971f79b615c1014c75e2f99f34bd4b4da542ca9f31d5ea7fadc4e9de39c1",
|
||||
"zh:46099a750c752ce05aa14d663a86478a5ad66d95aff3d69367f1d3628aac7792",
|
||||
"zh:71e56006b013dcfe1e4e059b2b07148b44fcd79351ae2c357e0d97e27ae0d916",
|
||||
"zh:74febd25d776688f0558178c2f5a0e6818bbf4cdaa2e160d7049da04103940f0",
|
||||
"h1:VSnd9ZIPyfKHOObuQCaKfnjIHRtR7qTw19Rz8tJxm+k=",
|
||||
"zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64",
|
||||
"zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d",
|
||||
"zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831",
|
||||
"zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3",
|
||||
"zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:af18c064a5f0dd5422d6771939274841f635b619ab392c73d5bf9720945fdb85",
|
||||
"zh:c133d7a862079da9f06e301c530eacbd70e9288fa2276ec0704df907270ee328",
|
||||
"zh:c894cf98d239b9f5a4b7cde9f5c836face0b5b93099048ee817b0380ea439c65",
|
||||
"zh:c918642870f0cafdbe4d7dd07c909701fc3ddb47cac8357bdcde1327bf78c11d",
|
||||
"zh:f8f5655099a57b4b9c0018a2d49133771e24c7ff8262efb1ceb140fd224aa9b6",
|
||||
"zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b",
|
||||
"zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2",
|
||||
"zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865",
|
||||
"zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03",
|
||||
"zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602",
|
||||
"zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014",
|
||||
]
|
||||
}
|
||||
|
@ -1,69 +0,0 @@
|
||||
job "adminer" {
|
||||
datacenters = ["dc1"]
|
||||
type = "service"
|
||||
|
||||
group "adminer" {
|
||||
count = 1
|
||||
# Some affinity to stateful hosts?
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
port "adminer" {
|
||||
host_network = "loopback"
|
||||
to = 8080
|
||||
}
|
||||
}
|
||||
|
||||
service {
|
||||
name = "adminer"
|
||||
port = "adminer"
|
||||
|
||||
connect {
|
||||
sidecar_service {
|
||||
proxy {
|
||||
local_service_port = 8080
|
||||
|
||||
upstreams {
|
||||
destination_name = "mysql-server"
|
||||
local_bind_port = 4040
|
||||
}
|
||||
|
||||
config {
|
||||
protocol = "tcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sidecar_task {
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 25
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.adminer.entryPoints=websecure",
|
||||
]
|
||||
}
|
||||
|
||||
task "adminer" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "adminer"
|
||||
ports = ["adminer"]
|
||||
}
|
||||
|
||||
env = {
|
||||
"ADMINER_DEFAULT_SERVER" = "${NOMAD_UPSTREAM_ADDR_mysql_server}"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
253
databases/lldap.nomad
Normal file
253
databases/lldap.nomad
Normal file
@ -0,0 +1,253 @@
|
||||
job "lldap" {
|
||||
datacenters = ["dc1"]
|
||||
type = "service"
|
||||
priority = 80
|
||||
|
||||
update {
|
||||
auto_revert = true
|
||||
}
|
||||
|
||||
group "lldap" {
|
||||
|
||||
network {
|
||||
mode = "bridge"
|
||||
|
||||
port "web" {
|
||||
%{~ if use_wesher ~}
|
||||
host_network = "wesher"
|
||||
%{~ endif ~}
|
||||
}
|
||||
|
||||
port "ldap" {
|
||||
%{~ if use_wesher ~}
|
||||
host_network = "wesher"
|
||||
%{~ endif ~}
|
||||
}
|
||||
|
||||
port "tls" {}
|
||||
}
|
||||
|
||||
service {
|
||||
name = "lldap"
|
||||
provider = "nomad"
|
||||
port = "ldap"
|
||||
}
|
||||
|
||||
service {
|
||||
name = "lldap-tls"
|
||||
provider = "nomad"
|
||||
port = "tls"
|
||||
}
|
||||
|
||||
service {
|
||||
name = "ldap-admin"
|
||||
provider = "nomad"
|
||||
port = "web"
|
||||
|
||||
tags = [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.ldap-admin.entryPoints=websecure",
|
||||
]
|
||||
}
|
||||
|
||||
task "lldap" {
|
||||
driver = "docker"
|
||||
|
||||
config {
|
||||
image = "ghcr.io/lldap/lldap:v0.5"
|
||||
ports = ["ldap", "web"]
|
||||
args = ["run", "--config-file", "$${NOMAD_TASK_DIR}/lldap_config.toml"]
|
||||
}
|
||||
|
||||
env = {
|
||||
"LLDAP_VERBOSE" = "true"
|
||||
"LLDAP_LDAP_PORT" = "$${NOMAD_PORT_ldap}"
|
||||
"LLDAP_HTTP_PORT" = "$${NOMAD_PORT_web}"
|
||||
"LLDAP_DATABASE_URL_FILE" = "$${NOMAD_SECRETS_DIR}/database_url.txt"
|
||||
"LLDAP_KEY_SEED_FILE" = "$${NOMAD_SECRETS_DIR}/key_seed.txt"
|
||||
"LLDAP_JWT_SECRET_FILE" = "$${NOMAD_SECRETS_DIR}/jwt_secret.txt"
|
||||
"LLDAP_USER_PASS_FILE" = "$${NOMAD_SECRETS_DIR}/user_pass.txt"
|
||||
"LLDAP_SMTP_OPTIONS__PASSWORD_FILE" = "$${NOMAD_SECRETS_DIR}/smtp_password.txt"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOH
|
||||
ldap_base_dn = "{{ with nomadVar "nomad/jobs" }}{{ .ldap_base_dn }}{{ end }}"
|
||||
|
||||
{{ with nomadVar "secrets/ldap" -}}
|
||||
ldap_user_dn = "{{ .admin_user }}"
|
||||
ldap_user_email = "{{ .admin_email }}"
|
||||
{{ end -}}
|
||||
|
||||
{{ with nomadVar "nomad/jobs/lldap" -}}
|
||||
[smtp_options]
|
||||
from = "{{ .smtp_from }}"
|
||||
reply_to = "{{ .smtp_reply_to }}"
|
||||
enable_password_reset = true
|
||||
{{ end -}}
|
||||
{{ with nomadVar "secrets/smtp" -}}
|
||||
server = "{{ .server }}"
|
||||
port = {{ .port }}
|
||||
tls_required = {{ .tls.Value | toLower }}
|
||||
user = "{{ .user }}"
|
||||
{{ end -}}
|
||||
EOH
|
||||
destination = "$${NOMAD_TASK_DIR}/lldap_config.toml"
|
||||
change_mode = "restart"
|
||||
}
|
||||
|
||||
template {
|
||||
data = "{{ with nomadVar \"nomad/jobs/lldap\" }}mysql://{{ .db_user }}:{{ .db_pass }}@127.0.0.1:3306/{{ .db_name }}{{ end }}"
|
||||
destination = "$${NOMAD_SECRETS_DIR}/database_url.txt"
|
||||
change_mode = "restart"
|
||||
}
|
||||
|
||||
template {
|
||||
data = "{{ with nomadVar \"nomad/jobs/lldap\" }}{{ .key_seed }}{{ end }}"
|
||||
destination = "$${NOMAD_SECRETS_DIR}/key_seed.txt"
|
||||
change_mode = "restart"
|
||||
}
|
||||
|
||||
template {
|
||||
data = "{{ with nomadVar \"nomad/jobs/lldap\" }}{{ .jwt_secret }}{{ end }}"
|
||||
destination = "$${NOMAD_SECRETS_DIR}/jwt_secret.txt"
|
||||
change_mode = "restart"
|
||||
}
|
||||
|
||||
template {
|
||||
data = "{{ with nomadVar \"secrets/ldap\" }}{{ .admin_password }}{{ end }}"
|
||||
destination = "$${NOMAD_SECRETS_DIR}/user_pass.txt"
|
||||
change_mode = "restart"
|
||||
}
|
||||
|
||||
template {
|
||||
data = "{{ with nomadVar \"secrets/smtp\" }}{{ .password }}{{ end }}"
|
||||
destination = "$${NOMAD_SECRETS_DIR}/smtp_password.txt"
|
||||
change_mode = "restart"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 10
|
||||
memory = 200
|
||||
memory_max = 200
|
||||
}
|
||||
}
|
||||
|
||||
task "bootstrap" {
|
||||
driver = "docker"
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = false
|
||||
}
|
||||
|
||||
config {
|
||||
image = "mariadb:10"
|
||||
args = [
|
||||
"/usr/bin/timeout",
|
||||
"20m",
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
"until /usr/bin/mysql --defaults-extra-file=$${NOMAD_SECRETS_DIR}/my.cnf < $${NOMAD_SECRETS_DIR}/bootstrap.sql; do sleep 10; done",
|
||||
]
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
[client]
|
||||
host=127.0.0.1
|
||||
port=3306
|
||||
user=root
|
||||
{{ with nomadVar "secrets/mysql" -}}
|
||||
password={{ .mysql_root_password }}
|
||||
{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/my.cnf"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ with nomadVar "nomad/jobs/lldap" -}}
|
||||
{{ $db_name := .db_name }}
|
||||
CREATE DATABASE IF NOT EXISTS `{{ .db_name }}`
|
||||
CHARACTER SET = 'utf8mb4'
|
||||
COLLATE = 'utf8mb4_unicode_ci';
|
||||
DROP USER IF EXISTS '{{ .db_user }}'@'%';
|
||||
CREATE USER '{{ .db_user }}'@'%'
|
||||
IDENTIFIED BY '{{ .db_pass }}';
|
||||
GRANT ALL ON `{{ .db_name }}`.*
|
||||
TO '{{ .db_user }}'@'%';
|
||||
{{ else -}}
|
||||
SELECT 'NOOP';
|
||||
{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/bootstrap.sql"
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 50
|
||||
memory = 50
|
||||
}
|
||||
}
|
||||
|
||||
task "stunnel" {
|
||||
driver = "docker"
|
||||
|
||||
lifecycle {
|
||||
hook = "prestart"
|
||||
sidecar = true
|
||||
}
|
||||
|
||||
config {
|
||||
image = "iamthefij/stunnel:1.0.0"
|
||||
args = ["$${NOMAD_TASK_DIR}/stunnel.conf"]
|
||||
ports = ["tls"]
|
||||
}
|
||||
|
||||
resources {
|
||||
cpu = 100
|
||||
memory = 100
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
syslog = no
|
||||
foreground = yes
|
||||
delay = yes
|
||||
|
||||
[ldap_server]
|
||||
accept = {{ env "NOMAD_PORT_tls" }}
|
||||
connect = 127.0.0.1:{{ env "NOMAD_PORT_ldap" }}
|
||||
ciphers = PSK
|
||||
PSKsecrets = {{ env "NOMAD_SECRETS_DIR" }}/stunnel_psk.txt
|
||||
|
||||
[mysql_client]
|
||||
client = yes
|
||||
accept = 127.0.0.1:3306
|
||||
{{ range nomadService 1 (env "NOMAD_ALLOC_ID") "mysql-tls" -}}
|
||||
connect = {{ .Address }}:{{ .Port }}
|
||||
{{- end }}
|
||||
PSKsecrets = {{ env "NOMAD_SECRETS_DIR" }}/mysql_stunnel_psk.txt
|
||||
EOF
|
||||
destination = "$${NOMAD_TASK_DIR}/stunnel.conf"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{ range nomadVarList "secrets/ldap/allowed_psks" -}}
|
||||
{{ with nomadVar .Path }}{{ .psk }}{{ end }}
|
||||
{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/stunnel_psk.txt"
|
||||
}
|
||||
|
||||
template {
|
||||
data = <<EOF
|
||||
{{- with nomadVar "secrets/mysql/allowed_psks/lldap" }}{{ .psk }}{{ end -}}
|
||||
EOF
|
||||
destination = "$${NOMAD_SECRETS_DIR}/mysql_stunnel_psk.txt"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
123
databases/lldap.tf
Normal file
123
databases/lldap.tf
Normal file
@ -0,0 +1,123 @@
|
||||
resource "nomad_job" "lldap" {
|
||||
jobspec = templatefile("${path.module}/lldap.nomad", {
|
||||
use_wesher = var.use_wesher,
|
||||
})
|
||||
|
||||
depends_on = [resource.nomad_job.mysql-server]
|
||||
|
||||
# Block until deployed as there are servics dependent on this one
|
||||
detach = false
|
||||
}
|
||||
|
||||
# Give access to ldap secrets
|
||||
resource "nomad_acl_policy" "lldap_ldap_secrets" {
|
||||
name = "lldap-secrets-ldap"
|
||||
description = "Give access to LDAP secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/ldap/*" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
path "secrets/ldap" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
# job_id = resource.nomad_job.lldap.id
|
||||
job_id = "lldap"
|
||||
}
|
||||
}
|
||||
|
||||
# Create self-scoped psk so that config is valid at first start
|
||||
resource "random_password" "lldap_ldap_psk" {
|
||||
length = 32
|
||||
override_special = "!@#%&*-_="
|
||||
}
|
||||
|
||||
resource "nomad_variable" "lldap_ldap_psk" {
|
||||
path = "secrets/ldap/allowed_psks/ldap"
|
||||
items = {
|
||||
psk = "lldap:${resource.random_password.lldap_ldap_psk.result}"
|
||||
}
|
||||
}
|
||||
|
||||
# Give access to smtp secrets
|
||||
resource "nomad_acl_policy" "lldap_smtp_secrets" {
|
||||
name = "lldap-secrets-smtp"
|
||||
description = "Give access to SMTP secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/smtp" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
# job_id = resource.nomad_job.lldap.id
|
||||
job_id = "lldap"
|
||||
group = "lldap"
|
||||
task = "lldap"
|
||||
}
|
||||
}
|
||||
|
||||
# Generate secrets and policies for access to MySQL
|
||||
resource "nomad_acl_policy" "lldap_mysql_bootstrap_secrets" {
|
||||
name = "lldap-secrets-mysql"
|
||||
description = "Give access to MySQL secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/mysql" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
# job_id = resource.nomad_job.lldap.id
|
||||
job_id = "lldap"
|
||||
group = "lldap"
|
||||
task = "bootstrap"
|
||||
}
|
||||
}
|
||||
|
||||
resource "random_password" "lldap_mysql_psk" {
|
||||
length = 32
|
||||
override_special = "!@#%&*-_="
|
||||
}
|
||||
|
||||
resource "nomad_variable" "lldap_mysql_psk" {
|
||||
path = "secrets/mysql/allowed_psks/lldap"
|
||||
items = {
|
||||
psk = "lldap:${resource.random_password.lldap_mysql_psk.result}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "nomad_acl_policy" "lldap_mysql_psk" {
|
||||
name = "lldap-secrets-mysql-psk"
|
||||
description = "Give access to MySQL PSK secrets"
|
||||
rules_hcl = <<EOH
|
||||
namespace "default" {
|
||||
variables {
|
||||
path "secrets/mysql/allowed_psks/lldap" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
}
|
||||
}
|
||||
EOH
|
||||
|
||||
job_acl {
|
||||
# job_id = resource.nomad_job.lldap.id
|
||||
job_id = "lldap"
|
||||
group = "lldap"
|
||||
task = "stunnel"
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user