Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LDAP secret engine support (#1032) #1033

Merged
merged 28 commits into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5d526ba
Initial commit for LDAP secrets engine
JordanStopford Aug 23, 2023
1b5aaad
Fix docs and linting issues
JordanStopford Aug 29, 2023
682d5eb
Fix linting error
JordanStopford Sep 4, 2023
df51d22
Run tests with docker container so we don't need to install vault
JordanStopford Mar 13, 2024
2dc7358
More tests
JordanStopford Mar 13, 2024
d1f5fd2
Merge branch 'main' into ldap-secrets
JordanStopford Mar 13, 2024
922bc96
Fix indentation
JordanStopford Mar 13, 2024
72258d3
Fix client not being available
JordanStopford Mar 13, 2024
1161ea4
Various test fixes
JordanStopford Mar 13, 2024
3adf09f
Merge branch 'hvac:main' into ldap-secrets
JordanStopford Mar 20, 2024
0feed5c
Reverting the changes prior to implementing unit tests
JordanStopford Mar 20, 2024
deb7d5b
Reverting the changes prior to implementing unit tests
JordanStopford Mar 20, 2024
c6221ae
Reverting the changes prior to implementing unit tests
JordanStopford Mar 20, 2024
a6a2602
Unit tests for LDAP secrets
JordanStopford Mar 20, 2024
f8e56cd
Reverting the changes prior to implementing unit tests
JordanStopford Mar 20, 2024
cda852f
Linting
JordanStopford Mar 20, 2024
0dc0cc4
Fix newline?
JordanStopford Mar 20, 2024
776db59
Fix newline?
JordanStopford Mar 20, 2024
777f961
Fix linting
JordanStopford Mar 20, 2024
476f6bc
Merge branch 'hvac:main' into ldap-secrets
JordanStopford Mar 22, 2024
a53faba
Apply suggestions from code review
briantist Apr 13, 2024
6a5d830
Update hvac/api/secrets_engines/ldap.py
briantist Apr 13, 2024
bd4b2a9
nit: remove docs character
briantist Apr 13, 2024
c705eb9
remove use of arbitrary kwargs
briantist Apr 13, 2024
d07671a
use example.com in tests
briantist Apr 13, 2024
cbe3f83
add unit test for generate_static_credentials
briantist Apr 13, 2024
f199003
Merge branch 'main' into pr/JordanStopford/1033
briantist Apr 13, 2024
d166125
Merge branch 'main' into pr/JordanStopford/1033
briantist Apr 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge branch 'main' into ldap-secrets
  • Loading branch information
JordanStopford committed Mar 13, 2024
commit d1f5fd2169ba367b351d673c4c84a4d84a7cd30b
4 changes: 2 additions & 2 deletions tests/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ def vault_running_inside_docker():
def get_vault_version_string():
if "cache" in get_vault_version_string.__dict__:
return get_vault_version_string.cache

command = ["vault", "-version"]
container = vault_running_inside_docker()
if not container:
if not find_executable("vault"):
if not which("vault"):
raise SkipTest("Vault executable not found")
else:
command = ["docker", "exec", container] + command
Expand Down
28 changes: 20 additions & 8 deletions tests/utils/hvac_integration_test_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,26 @@ def setUpClass(cls):
config_paths=config_paths,
use_consul=cls.enable_vault_ha,
)
try:
cls.manager.start()
cls.manager.initialize()
cls.manager.unseal()
cls.manager.configure()
except Exception as e:
cls.manager.stop()
raise

while True:
try:
cls.manager.start()
cls.manager.initialize()
cls.manager.unseal()
cls.manager.configure()
except Exception as e:
cls.manager.stop()
logging.debug(
f"Failure in ServerManager (retries remaining: {cls.server_retry_count})\n{str(e)}"
)
if cls.server_retry_count > 0:
cls.server_retry_count -= 1
time.sleep(cls.server_retry_delay_seconds)
else:
raise
else:
break


@classmethod
def tearDownClass(cls):
Expand Down
138 changes: 69 additions & 69 deletions tests/utils/server_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@

import distutils.spawn
from unittest import SkipTest
from tests.utils import get_config_file_path, load_config_file, create_client, vault_running_inside_docker
from tests.utils import (
get_config_file_path,
load_config_file,
create_client,
PortGetter,
vault_running_inside_docker,
)

from hvac.v1 import Client

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -126,6 +134,10 @@ def start(self):
}
self.start_vault(consul_config=consul_config)

def start_vault(
self, *, consul_config: dict = None, attempt=1, max_attempts=3, delay_s=1
):
"""Launch the vault server process and wait until its online and ready."""
pre_cmd = []
container = vault_running_inside_docker()
if not container:
Expand All @@ -134,22 +146,26 @@ def start(self):
else:
pre_cmd = ["docker", "exec", container]

# If a vault server is already running then we won't be able to start another one.
# If we can't start our vault server then we don't know what we're testing against.
try:
self.client.sys.is_initialized()
except Exception as e:
pass
else:
if container:
return
raise Exception("Vault server already running")

if container:
return # We are already configured
with PortGetter() as g:
self.active_config_paths = [
self.patch_config_port(
config_path,
port_getter=g.get_port,
insert=True,
additional_sections=consul_config,
)
if self.patch_config
else config_path
for config_path in self.config_paths
]

cluster_ready = False
for config_path in self.config_paths:
for config_path in self.active_config_paths:
this_addr = self.get_config_vault_address(config_path)
this_client = create_client(url=this_addr)
if self.client is None:
self.client = this_client

command = pre_cmd + ["vault", "server", "-config=" + config_path]
logger.debug(f"Starting vault server with command: {command}")
process = subprocess.Popen(
Expand All @@ -170,7 +186,21 @@ def start(self):
break
except Exception as ex:
if process.poll() is not None:
raise Exception("Vault server terminated before becoming ready")
stdout, stderr = process.stdout, process.stderr
if attempt < max_attempts:
logger.debug(
f"Starting Vault failed (attempt {attempt} of {max_attempts}):\n{last_exception}\n{stdout.readlines()}\n{stderr.readlines()}"
)
time.sleep(delay_s)
self.start_vault(
attempt=(attempt + 1),
max_attempts=max_attempts,
delay_s=delay_s,
)
else:
raise Exception(
"Vault server terminated before becoming ready"
)

logger.debug("Waiting for Vault to start")
time.sleep(0.5)
Expand Down Expand Up @@ -278,10 +308,14 @@ def stop(self):
if container:
return

for process_num, process in enumerate(self._processes):
logger.debug(f"Terminating vault server with PID {process.pid}")
if process.poll() is None:
process.kill()
self.client = None
for process_num, pinfo in reversed(list(enumerate(self._processes))):
logger.debug(
f"Terminating {pinfo.name} server with PID {pinfo.process.pid}"
)
if pinfo.process.poll() is None:
pinfo.process.kill()

if os.getenv("HVAC_OUTPUT_VAULT_STDERR", False):
try:
stdout_lines, stderr_lines = pinfo.process.communicate()
Expand All @@ -306,35 +340,10 @@ def stop(self):

def initialize(self):
"""Perform initialization of the vault server process and record the provided unseal keys and root token."""
container = vault_running_inside_docker()
"""
if container:
#time.sleep(5)
# We can't init externally, need to run it inside the container directly
command = ['docker', 'exec', container, 'vault', 'operator', 'init']
process = subprocess.Popen(command, stdout=subprocess.PIPE)
output, _ = process.communicate()
output = output.decode().splitlines()
keys = []
token = None
for line in output:
if 'Unseal Key' in line:
keys.append(line.split(':')[1].strip())
if 'Initial Root Token' in line:
token = line.split(':')[1].strip()

self.keys = keys
self.root_token = token
else:
# Container has hardcoded token
assert not self.client.sys.is_initialized()

result = self.client.sys.initialize()

self.root_token = result["root_token"]
self.keys = result["keys"]
"""
assert not self.client.sys.is_initialized()
if self.client.sys.is_initialized():
raise RuntimeError(
f"Vault is already initialized: {self.get_active_vault_addresses()}"
)

result = self.client.sys.initialize(secret_shares=5, secret_threshold=3)

Expand Down Expand Up @@ -367,32 +376,23 @@ def get_config_vault_address(self, config_path: str) -> str:

def get_active_vault_addresses(self):
vault_addresses = []
for config_path in self.config_paths:
config_hcl = load_config_file(config_path)
config = hcl.loads(config_hcl)
try:
vault_address = "https://{addr}".format(
addr=config["listener"]["tcp"]["address"]
)
# Force use of localhost if we're serving locally
vault_address = vault_address.replace('0.0.0.0', '127.0.0.1')
except KeyError as error:
logger.debug(
"Unable to find explict Vault address in config file {path}: {err}".format(
path=config_path,
err=error,
)
)
vault_address = "https://127.0.0.1:8200"
logger.debug(f"Using default address: {vault_address}")
vault_addresses.append(vault_address)
config_paths = (
self.active_config_paths
if self.active_config_paths is not None
else self.config_paths
)
for config_path in config_paths:
vault_addr = self.get_config_vault_address(config_path)
vault_addr = vault_addr.replace('0.0.0.0', '127.0.0.1')
vault_addresses.append(vault_addr)
return vault_addresses

def unseal(self):
"""Unseal the vault server process."""
vault_addresses = self.get_active_vault_addresses()
for vault_address in vault_addresses:
create_client(url=vault_address).sys.submit_unseal_keys(self.keys)
client = create_client(url=vault_address)
client.sys.submit_unseal_keys(self.keys)

def configure(self):
"""Configure any pre-requisites for tests."""
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.