Skip to content

Commit af158e2

Browse files
authored
feat: improve makejinja functions and cloudflared deployment (#1824)
Signed-off-by: Devin Buhl <devin@buhl.casa>
1 parent 4628682 commit af158e2

File tree

6 files changed

+86
-67
lines changed

6 files changed

+86
-67
lines changed

templates/config/.sops.yaml.j2

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
creation_rules:
33
- path_regex: talos/.*\.sops\.ya?ml
44
mac_only_encrypted: true
5-
age: "#{ age_public_key() }#"
5+
age: "#{ age_key('public') }#"
66
- path_regex: (bootstrap|kubernetes)/.*\.sops\.ya?ml
77
encrypted_regex: "^(data|stringData)$"
88
mac_only_encrypted: true
9-
age: "#{ age_public_key() }#"
9+
age: "#{ age_key('public') }#"
1010
stores:
1111
yaml:
1212
indent: 2

templates/config/kubernetes/apps/network/external/cloudflared/dnsendpoint.yaml.j2

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ spec:
88
endpoints:
99
- dnsName: "external.${SECRET_DOMAIN}"
1010
recordType: CNAME
11-
targets: ["#{ cloudflare_tunnel('TunnelID') }#.cfargotunnel.com"]
11+
targets: ["#{ cloudflare_tunnel_id() }#.cfargotunnel.com"]

templates/config/kubernetes/apps/network/external/cloudflared/helmrelease.yaml.j2

+4-12
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,14 @@ spec:
2929
tag: 2025.2.1
3030
env:
3131
NO_AUTOUPDATE: true
32-
TUNNEL_CRED_FILE: /etc/cloudflared/credentials.json
3332
TUNNEL_METRICS: 0.0.0.0:8080
3433
TUNNEL_ORIGIN_ENABLE_HTTP2: true
3534
TUNNEL_POST_QUANTUM: true
3635
TUNNEL_TRANSPORT_PROTOCOL: quic
37-
args:
38-
- tunnel
39-
- run
40-
- #{ cloudflare_tunnel('TunnelID') }#
36+
envFrom:
37+
- secretRef:
38+
name: cloudflared-secret
39+
args: ["tunnel", "run"]
4140
probes:
4241
liveness: &probes
4342
enabled: true
@@ -89,10 +88,3 @@ spec:
8988
- path: /etc/cloudflared/config.yaml
9089
subPath: config.yaml
9190
readOnly: true
92-
creds:
93-
type: secret
94-
name: cloudflared-secret
95-
globalMounts:
96-
- path: /etc/cloudflared/credentials.json
97-
subPath: credentials.json
98-
readOnly: true

templates/config/kubernetes/apps/network/external/cloudflared/secret.sops.yaml.j2

+2-6
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,5 @@ kind: Secret
55
metadata:
66
name: cloudflared-secret
77
stringData:
8-
credentials.json: |
9-
{
10-
"AccountTag": "#{ cloudflare_tunnel('AccountTag') }#",
11-
"TunnelSecret": "#{ cloudflare_tunnel('TunnelSecret') }#",
12-
"TunnelID": "#{ cloudflare_tunnel('TunnelID') }#"
13-
}
8+
TUNNEL_TOKEN: |
9+
#{ cloudflare_tunnel_secret() }#

templates/config/kubernetes/components/common/sops-age.sops.yaml.j2

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ kind: Secret
44
metadata:
55
name: sops-age
66
stringData:
7-
age.agekey: "#{ age_private_key() }#"
7+
age.agekey: "#{ age_key('private') }#"

templates/scripts/plugin.py

+76-45
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import Any
33
from netaddr import IPNetwork
44

5+
import base64
56
import makejinja
67
import re
78
import json
@@ -24,62 +25,92 @@ def nthhost(value: str, query: int) -> str:
2425
return value
2526

2627

27-
# Return the age public key from age.key
28-
def age_public_key() -> str:
28+
# Return the age public or private key from age.key
29+
def age_key(key_type: str, file_path: str = 'age.key') -> str:
2930
try:
30-
with open('age.key', 'r') as file:
31+
with open(file_path, 'r') as file:
3132
file_content = file.read().strip()
32-
except FileNotFoundError as e:
33-
raise FileNotFoundError(f"File not found: age.key") from e
34-
key_match = re.search(r"# public key: (age1[\w]+)", file_content)
35-
if not key_match:
36-
raise ValueError("Could not find public key in age.key")
37-
return key_match.group(1)
38-
39-
40-
# Return the age private key from age.key
41-
def age_private_key() -> str:
42-
try:
43-
with open('age.key', 'r') as file:
44-
file_content = file.read().strip()
45-
except FileNotFoundError as e:
46-
raise FileNotFoundError(f"File not found: age.key") from e
47-
key_match = re.search(r"(AGE-SECRET-KEY-[\w]+)", file_content)
48-
if not key_match:
49-
raise ValueError("Could not find private key in age.key")
50-
return key_match.group(1)
33+
if key_type == 'public':
34+
key_match = re.search(r"# public key: (age1[\w]+)", file_content)
35+
if not key_match:
36+
raise ValueError("Could not find public key in the age key file.")
37+
return key_match.group(1)
38+
elif key_type == 'private':
39+
key_match = re.search(r"(AGE-SECRET-KEY-[\w]+)", file_content)
40+
if not key_match:
41+
raise ValueError("Could not find private key in the age key file.")
42+
return key_match.group(1)
43+
else:
44+
raise ValueError("Invalid key type. Use 'public' or 'private'.")
45+
except FileNotFoundError:
46+
raise FileNotFoundError(f"File not found: {file_path}")
47+
except Exception as e:
48+
raise RuntimeError(f"Unexpected error while processing {file_path}: {e}")
5149

5250

5351
# Return cloudflare tunnel fields from cloudflare-tunnel.json
54-
def cloudflare_tunnel(value: str) -> str:
52+
def cloudflare_tunnel_id(file_path: str = 'cloudflare-tunnel.json') -> str:
5553
try:
56-
with open('cloudflare-tunnel.json', 'r') as file:
57-
try:
58-
return json.load(file).get(value)
59-
except json.JSONDecodeError as e:
60-
raise ValueError(f"Could not decode cloudflare-tunnel.json file") from e
61-
except FileNotFoundError as e:
62-
raise FileNotFoundError(f"File not found: cloudflare-tunnel.json") from e
54+
with open(file_path, 'r') as file:
55+
data = json.load(file)
56+
tunnel_id = data.get("TunnelID")
57+
if tunnel_id is None:
58+
raise KeyError(f"Missing 'TunnelID' key in {file_path}")
59+
return tunnel_id
60+
61+
except FileNotFoundError:
62+
raise FileNotFoundError(f"File not found: {file_path}")
63+
except json.JSONDecodeError:
64+
raise ValueError(f"Could not decode JSON file: {file_path}")
65+
except KeyError as e:
66+
raise KeyError(f"Error in JSON structure: {e}")
67+
except Exception as e:
68+
raise RuntimeError(f"Unexpected error while processing {file_path}: {e}")
69+
70+
71+
# Return cloudflare tunnel fields from cloudflare-tunnel.json in TUNNEL_TOKEN format
72+
def cloudflare_tunnel_secret(file_path: str = 'cloudflare-tunnel.json') -> str:
73+
try:
74+
with open(file_path, 'r') as file:
75+
data = json.load(file)
76+
transformed_data = {
77+
"a": data["AccountTag"],
78+
"t": data["TunnelID"],
79+
"s": data["TunnelSecret"]
80+
}
81+
json_string = json.dumps(transformed_data, separators=(',', ':'))
82+
return base64.b64encode(json_string.encode('utf-8')).decode('utf-8')
83+
84+
except FileNotFoundError:
85+
raise FileNotFoundError(f"File not found: {file_path}")
86+
except json.JSONDecodeError:
87+
raise ValueError(f"Could not decode JSON file: {file_path}")
88+
except KeyError as e:
89+
raise KeyError(f"Missing key in JSON file {file_path}: {e}")
90+
except Exception as e:
91+
raise RuntimeError(f"Unexpected error while processing {file_path}: {e}")
6392

6493

6594
# Return the GitHub deploy key from github-deploy.key
66-
def github_deploy_key() -> str:
95+
def github_deploy_key(file_path: str = 'github-deploy.key') -> str:
6796
try:
68-
with open('github-deploy.key', 'r') as file:
69-
file_content = file.read().strip()
70-
except FileNotFoundError as e:
71-
raise FileNotFoundError(f"File not found: github-deploy.key") from e
72-
return file_content
97+
with open(file_path, 'r') as file:
98+
return file.read().strip()
99+
except FileNotFoundError:
100+
raise FileNotFoundError(f"File not found: {file_path}")
101+
except Exception as e:
102+
raise RuntimeError(f"Unexpected error while reading {file_path}: {e}")
73103

74104

75105
# Return the Flux / GitHub push token from github-push-token.txt
76-
def github_push_token() -> str:
106+
def github_push_token(file_path: str = 'github-push-token.txt') -> str:
77107
try:
78-
with open('github-push-token.txt', 'r') as file:
79-
file_content = file.read().strip()
80-
except FileNotFoundError as e:
81-
raise FileNotFoundError(f"File not found: github-push-token.txt") from e
82-
return file_content
108+
with open(file_path, 'r') as file:
109+
return file.read().strip()
110+
except FileNotFoundError:
111+
raise FileNotFoundError(f"File not found: {file_path}")
112+
except Exception as e:
113+
raise RuntimeError(f"Unexpected error while reading {file_path}: {e}")
83114

84115

85116
# Return a list of files in the talos patches directory
@@ -129,9 +160,9 @@ def filters(self) -> makejinja.plugin.Filters:
129160

130161
def functions(self) -> makejinja.plugin.Functions:
131162
return [
132-
age_private_key,
133-
age_public_key,
134-
cloudflare_tunnel,
163+
age_key,
164+
cloudflare_tunnel_id,
165+
cloudflare_tunnel_secret,
135166
github_deploy_key,
136167
github_push_token,
137168
talos_patches

0 commit comments

Comments
 (0)