Skip to content

Commit d021d66

Browse files
committed
Avoid eager vault lookup for YAML secrets
Add load_yaml_file and reuse it in the CLI paths that read OpenStack, RabbitMQ, Octavia, and database secrets from YAML files. Several commands called get_vault() before checking whether the file was actually vault-encrypted. In deployments that keep secrets as plain YAML, this produced repeated 'Unable to get ansible vault password' errors for a path that is never needed. Read the file first and only initialize the vault when the content is encrypted. This removes noisy false-error output during checks and deployments while preserving decryption for encrypted secrets. AI-assisted: Codex Signed-off-by: Roger Luethi <luethi@osism.tech>
1 parent e46dfe3 commit d021d66

File tree

5 files changed

+39
-95
lines changed

5 files changed

+39
-95
lines changed

osism/commands/loadbalancer.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,9 @@ def _load_octavia_database_password():
3939
return None
4040

4141
try:
42-
from osism.tasks.conductor.utils import get_vault
42+
from osism.tasks.conductor.utils import load_yaml_file
4343

44-
vault = get_vault()
45-
46-
with open(secrets_path, "rb") as f:
47-
file_data = f.read()
48-
49-
if vault.is_encrypted(file_data):
50-
decrypted_data = vault.decrypt(file_data).decode()
51-
logger.debug(f"Successfully decrypted secrets file: {secrets_path}")
52-
else:
53-
decrypted_data = file_data.decode()
54-
logger.debug(
55-
f"Secrets file is not encrypted (development mode): {secrets_path}"
56-
)
57-
58-
secrets = yaml.safe_load(decrypted_data)
44+
secrets = load_yaml_file(secrets_path)
5945

6046
if not secrets or not isinstance(secrets, dict):
6147
logger.error("Empty or invalid secrets file")

osism/commands/status.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -104,30 +104,16 @@ def _load_kolla_configuration(self):
104104

105105
def _load_database_password(self):
106106
"""Load and decrypt the database password from secrets.yml"""
107-
from osism.tasks.conductor.utils import get_vault
108-
109107
secrets_path = "/opt/configuration/environments/kolla/secrets.yml"
110108

111109
if not os.path.exists(secrets_path):
112110
logger.error(f"Secrets file not found: {secrets_path}")
113111
return None
114112

115113
try:
116-
vault = get_vault()
117-
118-
with open(secrets_path, "rb") as f:
119-
file_data = f.read()
120-
121-
if vault.is_encrypted(file_data):
122-
decrypted_data = vault.decrypt(file_data).decode()
123-
logger.debug(f"Successfully decrypted secrets file: {secrets_path}")
124-
else:
125-
decrypted_data = file_data.decode()
126-
logger.debug(
127-
f"Secrets file is not encrypted (development mode): {secrets_path}"
128-
)
114+
from osism.tasks.conductor.utils import load_yaml_file
129115

130-
secrets = yaml.safe_load(decrypted_data)
116+
secrets = load_yaml_file(secrets_path)
131117

132118
if not secrets or not isinstance(secrets, dict):
133119
logger.error("Empty or invalid secrets file")

osism/tasks/conductor/utils.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
# SPDX-License-Identifier: Apache-2.0
22

3+
import os
4+
35
from ansible import constants as ansible_constants
46
from ansible.parsing.vault import VaultLib, VaultSecret
57
from loguru import logger
68

79
from osism import utils
810
import sushy
911
import urllib3
12+
import yaml
1013

1114

1215
def deep_compare(a, b, updates):
@@ -88,6 +91,32 @@ def get_vault():
8891
return vault
8992

9093

94+
def load_yaml_file(path):
95+
"""Load a YAML file and only request the vault secret when needed."""
96+
if not os.path.exists(path):
97+
logger.error(f"YAML file not found: {path}")
98+
return None
99+
100+
try:
101+
with open(path, "rb") as f:
102+
file_data = f.read()
103+
104+
if VaultLib().is_encrypted(file_data):
105+
decrypted_data = get_vault().decrypt(file_data).decode()
106+
logger.debug(f"Successfully decrypted vault-encrypted YAML file: {path}")
107+
else:
108+
decrypted_data = file_data.decode()
109+
logger.debug(f"YAML file is not encrypted: {path}")
110+
111+
return yaml.safe_load(decrypted_data)
112+
except yaml.YAMLError as exc:
113+
logger.error(f"Failed to parse YAML file {path}: {exc}")
114+
return None
115+
except Exception as exc:
116+
logger.error(f"Failed to load YAML file {path}: {exc}")
117+
return None
118+
119+
91120
def get_redfish_connection(
92121
hostname, username=None, password=None, ignore_ssl_errors=True, timeout=None
93122
):

osism/tasks/openstack.py

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from osism import settings, utils
1212
from osism.tasks import Config, run_command
13-
from osism.tasks.conductor.utils import get_vault
13+
from osism.tasks.conductor.utils import load_yaml_file
1414

1515
app = Celery("openstack")
1616
app.config_from_object(Config)
@@ -432,51 +432,9 @@ def get_cloud_password(cloud):
432432
logger.warning(f"Secrets file not found: {secrets_path}")
433433
return None
434434

435-
# Get vault instance for decryption
436-
vault = get_vault()
437-
438-
# Load the secrets file
439-
with open(secrets_path, "rb") as f:
440-
file_data = f.read()
441-
442-
decrypted_secrets = None
443-
444-
# Try to decrypt the file if it's vault encrypted
445-
try:
446-
if vault.is_encrypted(file_data):
447-
# File is encrypted, decrypt it
448-
decrypted_data = vault.decrypt(file_data).decode()
449-
logger.debug(f"Successfully decrypted secrets file: {secrets_path}")
450-
else:
451-
# File is not encrypted, use as-is
452-
decrypted_data = file_data.decode()
453-
logger.debug(
454-
f"Secrets file is not encrypted (development mode): {secrets_path}"
455-
)
456-
457-
# Parse the YAML content safely
458-
try:
459-
decrypted_secrets = yaml.safe_load(decrypted_data)
460-
except yaml.YAMLError as yaml_exc:
461-
logger.error(
462-
f"Failed to parse YAML content from secrets file: {yaml_exc}"
463-
)
464-
return None
465-
466-
except Exception as decrypt_exc:
467-
# If decryption fails, try reading as plain YAML (development fallback)
468-
logger.warning(
469-
f"Failed to decrypt secrets file, attempting to read as plain YAML: {decrypt_exc}"
470-
)
471-
try:
472-
with open(secrets_path, "r") as f:
473-
decrypted_secrets = yaml.safe_load(f)
474-
logger.debug(
475-
f"Successfully loaded unencrypted secrets file (development mode): {secrets_path}"
476-
)
477-
except Exception as plain_exc:
478-
logger.error(f"Failed to read secrets file as plain YAML: {plain_exc}")
479-
return None
435+
decrypted_secrets = load_yaml_file(secrets_path)
436+
if decrypted_secrets is None:
437+
return None
480438

481439
if not decrypted_secrets or not isinstance(decrypted_secrets, dict):
482440
logger.warning(

osism/utils/rabbitmq.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import subprocess
77

88
from loguru import logger
9-
import yaml
109

1110
from osism.utils.inventory import get_hosts_from_inventory, get_inventory_path
1211

@@ -150,23 +149,9 @@ def load_rabbitmq_password():
150149
return None
151150

152151
try:
153-
from osism.tasks.conductor.utils import get_vault
152+
from osism.tasks.conductor.utils import load_yaml_file
154153

155-
vault = get_vault()
156-
157-
with open(secrets_path, "rb") as f:
158-
file_data = f.read()
159-
160-
if vault.is_encrypted(file_data):
161-
decrypted_data = vault.decrypt(file_data).decode()
162-
logger.debug(f"Successfully decrypted secrets file: {secrets_path}")
163-
else:
164-
decrypted_data = file_data.decode()
165-
logger.debug(
166-
f"Secrets file is not encrypted (development mode): {secrets_path}"
167-
)
168-
169-
secrets = yaml.safe_load(decrypted_data)
154+
secrets = load_yaml_file(secrets_path)
170155

171156
if not secrets or not isinstance(secrets, dict):
172157
logger.error("Empty or invalid secrets file")

0 commit comments

Comments
 (0)