Skip to content

Commit 5b86c0c

Browse files
committed
added should_decrypt to allow partitioned environments
1 parent af34c34 commit 5b86c0c

File tree

4 files changed

+32
-23
lines changed

4 files changed

+32
-23
lines changed

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "stacks"
3-
version = "2.0.11"
3+
version = "2.0.12"
44
description = "Stacks, the Terraform code pre-processor"
55
readme = "README.md"
66
requires-python = ">=3.10"

src/stacks/cmd/preinit.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def preinit(ctx):
1515
"stacks_subenvironment": ctx.subenv or "",
1616
"stacks_instance": ctx.instance or "",
1717
"stacks_environments": {
18-
item.name: helpers.hcl2_read([item.joinpath("env.tfvars")]) # TODO: replace 'env.tfvars' with '*.tfvars' after all stacks have been upgraded to v2
18+
item.name: helpers.hcl2_read([item.joinpath("env.tfvars")], must_decrypt=False) # TODO: replace 'env.tfvars' with '*.tfvars' after all stacks have been upgraded to v2
1919
for item in ctx.envs_dir.iterdir()
2020
if item.is_dir() and item.joinpath("env.tfvars").exists()
2121
},

src/stacks/helpers/config.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
from .merge import merge
1010

1111

12-
def config_read(patterns, should_decrypt, decoderfunc, **decoderargs):
12+
def config_read(patterns, should_decrypt, must_decrypt, decoderfunc, **decoderargs):
1313
"""Read configuration files in 'patterns' using 'decoderfunc' and return their merged contents.
1414
1515
Keyword arguments:
1616
patterns[list]: patterns to configuration files, in ascending order of priority
17-
should_decrypt[bool]: whether to decrypt data or not
17+
should_decrypt[bool]: whether it should try to decrypt data or not
18+
must_decrypt[bool]: whether decryption should succeed (if False and fails, returns encrypted value)
1819
decoderfunc[function]: function that parses a given configuration file into a data structure
1920
decoderargs[dict]: keyword arguments to pass to decoderfunc
2021
"""
@@ -26,19 +27,19 @@ def config_read(patterns, should_decrypt, decoderfunc, **decoderargs):
2627
if path.is_file():
2728
with open(path, "r") as f:
2829
data = merge(data, decoderfunc(f, **decoderargs))
29-
return decrypt(data) if should_decrypt else data
30+
return decrypt(data, must_decrypt=must_decrypt) if should_decrypt else data
3031

3132

32-
def json_read(patterns, should_decrypt=True):
33-
return config_read(patterns, should_decrypt, json.load)
33+
def json_read(patterns, should_decrypt=True, must_decrypt=True):
34+
return config_read(patterns, should_decrypt, must_decrypt, json.load)
3435

3536

36-
def yaml_read(patterns, should_decrypt=True):
37-
return config_read(patterns, should_decrypt, yaml.safe_load)
37+
def yaml_read(patterns, should_decrypt=True, must_decrypt=True):
38+
return config_read(patterns, should_decrypt, must_decrypt, yaml.safe_load)
3839

3940

40-
def hcl2_read(patterns, should_decrypt=True):
41-
return config_read(patterns, should_decrypt, hcl2.load)
41+
def hcl2_read(patterns, should_decrypt=True, must_decrypt=True):
42+
return config_read(patterns, should_decrypt, must_decrypt, hcl2.load)
4243

4344

4445
def config_write(data, path, encoderfunc, **encoderargs):

src/stacks/helpers/crypto.py

+20-12
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,13 @@ def encrypt(public_key_path, string):
8484
return f"ENC[{symmetric_key_encrypted_base64};{encryptor_tag_base64};{init_vector_base64};{string_encrypted_base64}]"
8585

8686

87-
def decrypt(data, private_key_path=os.getenv("STACKS_PRIVATE_KEY_PATH")):
87+
def decrypt(data, private_key_path=os.getenv("STACKS_PRIVATE_KEY_PATH"), must_decrypt=True):
8888
"""Decrypt 'data' using 'private_key_path'.
8989
9090
Keyword arguments:
91-
private_key_path[pathlib.Path]: path to private key
9291
data[any]: any data structure
92+
private_key_path[pathlib.Path]: path to private key
93+
must_decrypt[bool]: whether decryption should succeed (if False and fails, returns encrypted value)
9394
"""
9495
if isinstance(data, str) and data.startswith("ENC[") and data.endswith("]"):
9596
(
@@ -105,14 +106,21 @@ def decrypt(data, private_key_path=os.getenv("STACKS_PRIVATE_KEY_PATH")):
105106
password=None,
106107
backend=cryptography.hazmat.backends.default_backend(),
107108
)
108-
symmetric_key = private_key.decrypt(
109-
base64.b64decode(symmetric_key_encrypted_base64.encode()),
110-
cryptography.hazmat.primitives.asymmetric.padding.OAEP(
111-
mgf=cryptography.hazmat.primitives.asymmetric.padding.MGF1(algorithm=cryptography.hazmat.primitives.hashes.SHA256()),
112-
algorithm=cryptography.hazmat.primitives.hashes.SHA256(),
113-
label=None,
114-
),
115-
)
109+
110+
try:
111+
symmetric_key = private_key.decrypt(
112+
base64.b64decode(symmetric_key_encrypted_base64.encode()),
113+
cryptography.hazmat.primitives.asymmetric.padding.OAEP(
114+
mgf=cryptography.hazmat.primitives.asymmetric.padding.MGF1(algorithm=cryptography.hazmat.primitives.hashes.SHA256()),
115+
algorithm=cryptography.hazmat.primitives.hashes.SHA256(),
116+
label=None,
117+
),
118+
)
119+
except ValueError as e:
120+
if must_decrypt:
121+
raise e
122+
else:
123+
return data
116124

117125
init_vector = base64.b64decode(init_vector_base64.encode())
118126

@@ -134,9 +142,9 @@ def decrypt(data, private_key_path=os.getenv("STACKS_PRIVATE_KEY_PATH")):
134142
return string_decrypted.decode("utf-8")
135143

136144
elif isinstance(data, list):
137-
return [decrypt(private_key_path=private_key_path, data=item) for item in data]
145+
return [decrypt(private_key_path=private_key_path, data=item, must_decrypt=must_decrypt) for item in data]
138146

139147
elif isinstance(data, dict):
140-
return {key: decrypt(private_key_path=private_key_path, data=value) for key, value in data.items()}
148+
return {key: decrypt(private_key_path=private_key_path, data=value, must_decrypt=must_decrypt) for key, value in data.items()}
141149

142150
return data

0 commit comments

Comments
 (0)