43
43
import re
44
44
import traceback
45
45
from subprocess import Popen , PIPE
46
+ from cryptography .fernet import Fernet
47
+ import base64
48
+ from pathlib import Path
49
+ import hashlib
46
50
47
51
TERRAFORM_DIR = os .environ .get ('ANSIBLE_TF_DIR' , os .getcwd ())
48
52
TERRAFORM_ENV = os .path .join (TERRAFORM_DIR , '.terraform/environment' )
@@ -383,7 +387,6 @@ def to_dict(self):
383
387
384
388
385
389
def _execute_shell ():
386
- encoding = 'utf-8'
387
390
tf_workspace = [TERRAFORM_PATH , 'workspace' , 'select' , TERRAFORM_WS_NAME ]
388
391
proc_ws = Popen (tf_workspace , cwd = TERRAFORM_DIR , stdout = PIPE ,
389
392
stderr = PIPE , universal_newlines = True )
@@ -403,10 +406,37 @@ def _execute_shell():
403
406
return json .loads (out_cmd )
404
407
405
408
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
+
406
424
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 " )
410
440
411
441
def _backup_ansible (inventory ):
412
442
# Crates a state backup in Ansible inventory format
0 commit comments