mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Cluster aes session rotation test
This commit is contained in:
parent
41d69cff5a
commit
67703832e6
5 changed files with 218 additions and 141 deletions
0
tests/pytests/integration/cluster/__init__.py
Normal file
0
tests/pytests/integration/cluster/__init__.py
Normal file
150
tests/pytests/integration/cluster/conftest.py
Normal file
150
tests/pytests/integration/cluster/conftest.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
import logging
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
import salt.utils.platform
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_shared_path(tmp_path):
|
||||
path = tmp_path / "cluster"
|
||||
path.mkdir()
|
||||
return path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_pki_path(cluster_shared_path):
|
||||
path = cluster_shared_path / "pki"
|
||||
path.mkdir()
|
||||
(path / "peers").mkdir()
|
||||
return path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_cache_path(cluster_shared_path):
|
||||
path = cluster_shared_path / "cache"
|
||||
path.mkdir()
|
||||
return path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_master_1(request, salt_factories, cluster_pki_path, cluster_cache_path):
|
||||
config_defaults = {
|
||||
"open_mode": True,
|
||||
"transport": request.config.getoption("--transport"),
|
||||
}
|
||||
config_overrides = {
|
||||
"interface": "127.0.0.1",
|
||||
"cluster_id": "master_cluster",
|
||||
"cluster_peers": [
|
||||
"127.0.0.2",
|
||||
"127.0.0.3",
|
||||
],
|
||||
"cluster_pki_dir": str(cluster_pki_path),
|
||||
"cache_dir": str(cluster_cache_path),
|
||||
}
|
||||
factory = salt_factories.salt_master_daemon(
|
||||
"127.0.0.1",
|
||||
defaults=config_defaults,
|
||||
overrides=config_overrides,
|
||||
extra_cli_arguments_after_first_start_failure=["--log-level=info"],
|
||||
)
|
||||
with factory.started(start_timeout=120):
|
||||
yield factory
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_master_2(salt_factories, cluster_master_1):
|
||||
if salt.utils.platform.is_darwin() or salt.utils.platform.is_freebsd():
|
||||
subprocess.check_output(["ifconfig", "lo0", "alias", "127.0.0.2", "up"])
|
||||
|
||||
config_defaults = {
|
||||
"open_mode": True,
|
||||
"transport": cluster_master_1.config["transport"],
|
||||
}
|
||||
config_overrides = {
|
||||
"interface": "127.0.0.2",
|
||||
"cluster_id": "master_cluster",
|
||||
"cluster_peers": [
|
||||
"127.0.0.1",
|
||||
"127.0.0.3",
|
||||
],
|
||||
"cluster_pki_dir": cluster_master_1.config["cluster_pki_dir"],
|
||||
"cache_dir": cluster_master_1.config["cache_dir"],
|
||||
}
|
||||
|
||||
# Use the same ports for both masters, they are binding to different interfaces
|
||||
for key in (
|
||||
"ret_port",
|
||||
"publish_port",
|
||||
):
|
||||
config_overrides[key] = cluster_master_1.config[key]
|
||||
factory = salt_factories.salt_master_daemon(
|
||||
"127.0.0.2",
|
||||
defaults=config_defaults,
|
||||
overrides=config_overrides,
|
||||
extra_cli_arguments_after_first_start_failure=["--log-level=info"],
|
||||
)
|
||||
with factory.started(start_timeout=120):
|
||||
yield factory
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_master_3(salt_factories, cluster_master_1):
|
||||
if salt.utils.platform.is_darwin() or salt.utils.platform.is_freebsd():
|
||||
subprocess.check_output(["ifconfig", "lo0", "alias", "127.0.0.3", "up"])
|
||||
|
||||
config_defaults = {
|
||||
"open_mode": True,
|
||||
"transport": cluster_master_1.config["transport"],
|
||||
}
|
||||
config_overrides = {
|
||||
"interface": "127.0.0.3",
|
||||
"cluster_id": "master_cluster",
|
||||
"cluster_peers": [
|
||||
"127.0.0.1",
|
||||
"127.0.0.2",
|
||||
],
|
||||
"cluster_pki_dir": cluster_master_1.config["cluster_pki_dir"],
|
||||
"cache_dir": cluster_master_1.config["cache_dir"],
|
||||
}
|
||||
|
||||
# Use the same ports for both masters, they are binding to different interfaces
|
||||
for key in (
|
||||
"ret_port",
|
||||
"publish_port",
|
||||
):
|
||||
config_overrides[key] = cluster_master_1.config[key]
|
||||
factory = salt_factories.salt_master_daemon(
|
||||
"127.0.0.3",
|
||||
defaults=config_defaults,
|
||||
overrides=config_overrides,
|
||||
extra_cli_arguments_after_first_start_failure=["--log-level=info"],
|
||||
)
|
||||
with factory.started(start_timeout=120):
|
||||
yield factory
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_minion_1(cluster_master_1):
|
||||
config_defaults = {
|
||||
"transport": cluster_master_1.config["transport"],
|
||||
}
|
||||
|
||||
port = cluster_master_1.config["ret_port"]
|
||||
addr = cluster_master_1.config["interface"]
|
||||
config_overrides = {
|
||||
"master": f"{addr}:{port}",
|
||||
"test.foo": "baz",
|
||||
}
|
||||
factory = cluster_master_1.salt_minion_daemon(
|
||||
"cluster-minion-1",
|
||||
defaults=config_defaults,
|
||||
overrides=config_overrides,
|
||||
extra_cli_arguments_after_first_start_failure=["--log-level=info"],
|
||||
)
|
||||
with factory.started(start_timeout=120):
|
||||
yield factory
|
|
@ -5,146 +5,16 @@ import pytest
|
|||
|
||||
import salt.utils.platform
|
||||
|
||||
|
||||
from tests.pytests.integration.cluster.conftest import (
|
||||
cluster_shared_path,
|
||||
cluster_pki_path,
|
||||
cluster_cache_path,
|
||||
cluster_master_1,
|
||||
cluster_master_2,
|
||||
cluster_master_3,
|
||||
cluster_minion_1,
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_shared_path(tmp_path):
|
||||
path = tmp_path / "cluster"
|
||||
path.mkdir()
|
||||
return path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_pki_path(cluster_shared_path):
|
||||
path = cluster_shared_path / "pki"
|
||||
path.mkdir()
|
||||
(path / "peers").mkdir()
|
||||
return path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_cache_path(cluster_shared_path):
|
||||
path = cluster_shared_path / "cache"
|
||||
path.mkdir()
|
||||
return path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_master_1(request, salt_factories, cluster_pki_path, cluster_cache_path):
|
||||
config_defaults = {
|
||||
"open_mode": True,
|
||||
"transport": request.config.getoption("--transport"),
|
||||
}
|
||||
config_overrides = {
|
||||
"interface": "127.0.0.1",
|
||||
"cluster_id": "master_cluster",
|
||||
"cluster_peers": [
|
||||
"127.0.0.2",
|
||||
"127.0.0.3",
|
||||
],
|
||||
"cluster_pki_dir": str(cluster_pki_path),
|
||||
"cache_dir": str(cluster_cache_path),
|
||||
}
|
||||
factory = salt_factories.salt_master_daemon(
|
||||
"127.0.0.1",
|
||||
defaults=config_defaults,
|
||||
overrides=config_overrides,
|
||||
extra_cli_arguments_after_first_start_failure=["--log-level=info"],
|
||||
)
|
||||
with factory.started(start_timeout=120):
|
||||
yield factory
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_master_2(salt_factories, cluster_master_1):
|
||||
if salt.utils.platform.is_darwin() or salt.utils.platform.is_freebsd():
|
||||
subprocess.check_output(["ifconfig", "lo0", "alias", "127.0.0.2", "up"])
|
||||
|
||||
config_defaults = {
|
||||
"open_mode": True,
|
||||
"transport": cluster_master_1.config["transport"],
|
||||
}
|
||||
config_overrides = {
|
||||
"interface": "127.0.0.2",
|
||||
"cluster_id": "master_cluster",
|
||||
"cluster_peers": [
|
||||
"127.0.0.1",
|
||||
"127.0.0.3",
|
||||
],
|
||||
"cluster_pki_dir": cluster_master_1.config["cluster_pki_dir"],
|
||||
"cache_dir": cluster_master_1.config["cache_dir"],
|
||||
}
|
||||
|
||||
# Use the same ports for both masters, they are binding to different interfaces
|
||||
for key in (
|
||||
"ret_port",
|
||||
"publish_port",
|
||||
):
|
||||
config_overrides[key] = cluster_master_1.config[key]
|
||||
factory = salt_factories.salt_master_daemon(
|
||||
"127.0.0.2",
|
||||
defaults=config_defaults,
|
||||
overrides=config_overrides,
|
||||
extra_cli_arguments_after_first_start_failure=["--log-level=info"],
|
||||
)
|
||||
with factory.started(start_timeout=120):
|
||||
yield factory
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_master_3(salt_factories, cluster_master_1):
|
||||
if salt.utils.platform.is_darwin() or salt.utils.platform.is_freebsd():
|
||||
subprocess.check_output(["ifconfig", "lo0", "alias", "127.0.0.3", "up"])
|
||||
|
||||
config_defaults = {
|
||||
"open_mode": True,
|
||||
"transport": cluster_master_1.config["transport"],
|
||||
}
|
||||
config_overrides = {
|
||||
"interface": "127.0.0.3",
|
||||
"cluster_id": "master_cluster",
|
||||
"cluster_peers": [
|
||||
"127.0.0.1",
|
||||
"127.0.0.2",
|
||||
],
|
||||
"cluster_pki_dir": cluster_master_1.config["cluster_pki_dir"],
|
||||
"cache_dir": cluster_master_1.config["cache_dir"],
|
||||
}
|
||||
|
||||
# Use the same ports for both masters, they are binding to different interfaces
|
||||
for key in (
|
||||
"ret_port",
|
||||
"publish_port",
|
||||
):
|
||||
config_overrides[key] = cluster_master_1.config[key]
|
||||
factory = salt_factories.salt_master_daemon(
|
||||
"127.0.0.3",
|
||||
defaults=config_defaults,
|
||||
overrides=config_overrides,
|
||||
extra_cli_arguments_after_first_start_failure=["--log-level=info"],
|
||||
)
|
||||
with factory.started(start_timeout=120):
|
||||
yield factory
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cluster_minion_1(cluster_master_1):
|
||||
config_defaults = {
|
||||
"transport": cluster_master_1.config["transport"],
|
||||
}
|
||||
|
||||
port = cluster_master_1.config["ret_port"]
|
||||
addr = cluster_master_1.config["interface"]
|
||||
config_overrides = {
|
||||
"master": f"{addr}:{port}",
|
||||
"test.foo": "baz",
|
||||
}
|
||||
factory = cluster_master_1.salt_minion_daemon(
|
||||
"cluster-minion-1",
|
||||
defaults=config_defaults,
|
||||
overrides=config_overrides,
|
||||
extra_cli_arguments_after_first_start_failure=["--log-level=info"],
|
||||
)
|
||||
with factory.started(start_timeout=120):
|
||||
yield factory
|
||||
|
|
57
tests/pytests/scenarios/cluster/test_cluster.py
Normal file
57
tests/pytests/scenarios/cluster/test_cluster.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
import pathlib
|
||||
import time
|
||||
import os
|
||||
|
||||
import salt.crypt
|
||||
|
||||
def test_cluster_key_rotation(
|
||||
cluster_master_1, cluster_master_2, cluster_master_3, cluster_minion_1,
|
||||
cluster_cache_path,
|
||||
):
|
||||
cli = cluster_master_2.salt_cli(timeout=120)
|
||||
ret = cli.run("test.ping", minion_tgt="cluster-minion-1")
|
||||
assert ret.data is True
|
||||
|
||||
# Validate the aes session key for all masters match
|
||||
keys = set()
|
||||
for master in (cluster_master_1, cluster_master_2, cluster_master_3,):
|
||||
config = cluster_minion_1.config.copy()
|
||||
config["master_uri"] = f"tcp://{master.config['interface']}:{master.config['ret_port']}"
|
||||
auth = salt.crypt.SAuth(config)
|
||||
auth.authenticate()
|
||||
assert "aes" in auth._creds
|
||||
keys.add(auth._creds["aes"])
|
||||
|
||||
assert len(keys) == 1
|
||||
orig_aes = keys.pop()
|
||||
|
||||
dfpath = pathlib.Path(cluster_master_1.config["cachedir"]) / ".dfn"
|
||||
assert not dfpath.exists()
|
||||
salt.crypt.dropfile(
|
||||
cluster_master_1.config["cachedir"],
|
||||
user=os.getlogin(),
|
||||
master_id=cluster_master_1.config["id"],
|
||||
)
|
||||
assert dfpath.exists()
|
||||
timeout = 2 * cluster_master_1.config["loop_interval"]
|
||||
start = time.monotonic()
|
||||
while True:
|
||||
if not dfpath.exists():
|
||||
break
|
||||
if time.monotonic() - start > timeout:
|
||||
assert False, f"Drop file never removed {dfpath}"
|
||||
|
||||
keys = set()
|
||||
|
||||
# Validate the aes session key for all masters match
|
||||
for master in (cluster_master_1, cluster_master_2, cluster_master_3,):
|
||||
config = cluster_minion_1.config.copy()
|
||||
config["master_uri"] = f"tcp://{master.config['interface']}:{master.config['ret_port']}"
|
||||
auth = salt.crypt.SAuth(config)
|
||||
auth.authenticate()
|
||||
assert "aes" in auth._creds
|
||||
keys.add(auth._creds["aes"])
|
||||
|
||||
assert len(keys) == 1
|
||||
# Validate the aes session key actually changed
|
||||
assert orig_aes != keys.pop()
|
Loading…
Add table
Reference in a new issue