Skip to content

Commit acdd98c

Browse files
committed
terraform: encrypt backup state
1 parent a6aef24 commit acdd98c

File tree

1 file changed

+34
-4
lines changed

1 file changed

+34
-4
lines changed

ansible/terraform.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
import re
4444
import traceback
4545
from subprocess import Popen, PIPE
46+
from cryptography.fernet import Fernet
47+
import base64
48+
from pathlib import Path
49+
import hashlib
4650

4751
TERRAFORM_DIR = os.environ.get('ANSIBLE_TF_DIR', os.getcwd())
4852
TERRAFORM_ENV = os.path.join(TERRAFORM_DIR, '.terraform/environment')
@@ -383,7 +387,6 @@ def to_dict(self):
383387

384388

385389
def _execute_shell():
386-
encoding = 'utf-8'
387390
tf_workspace = [TERRAFORM_PATH, 'workspace', 'select', TERRAFORM_WS_NAME]
388391
proc_ws = Popen(tf_workspace, cwd=TERRAFORM_DIR, stdout=PIPE,
389392
stderr=PIPE, universal_newlines=True)
@@ -403,10 +406,37 @@ def _execute_shell():
403406
return json.loads(out_cmd)
404407

405408

409+
def _get_encryption_key():
410+
"""Generate encryption key using CONSUL_HTTP_TOKEN"""
411+
key_file = Path(TERRAFORM_DIR) / '.terraform' / '.state_key'
412+
413+
consul_token = os.environ.get('CONSUL_HTTP_TOKEN')
414+
if not consul_token:
415+
raise ValueError("CONSUL_HTTP_TOKEN environment variable is required for state encryption")
416+
417+
# Generate a fixed-length key using SHA256
418+
hashed = hashlib.sha256(consul_token.encode()).digest()
419+
# Convert to URL-safe base64 encoding as required by Fernet
420+
key = base64.urlsafe_b64encode(hashed)
421+
422+
return key
423+
406424
def _backup_tf(tfstate):
407-
# Crates a state backup in case we lose Consul
408-
with open(TERRAFORM_BPK, 'w') as f:
409-
f.write(json.dumps(tfstate.state_json))
425+
"""Creates an encrypted state backup"""
426+
try:
427+
key = _get_encryption_key()
428+
cipher = Fernet(key)
429+
430+
state_data = json.dumps(tfstate.state_json).encode()
431+
encrypted_data = cipher.encrypt(state_data)
432+
433+
backup_path = Path(TERRAFORM_BPK)
434+
backup_path.parent.mkdir(parents=True, exist_ok=True)
435+
backup_path.write_bytes(encrypted_data)
436+
backup_path.chmod(0o600)
437+
438+
except Exception as e:
439+
sys.stderr.write(f"Warning: Failed to create encrypted state backup: {str(e)}\n")
410440

411441
def _backup_ansible(inventory):
412442
# Crates a state backup in Ansible inventory format

0 commit comments

Comments
 (0)