Skip to content

Commit 9eea2c8

Browse files
szachovyCopilot
andcommitted
Add VRRP authentication to prevent VIP hijacking
Generate 8-char VRRP password in crypto.py, add authentication block to keepalived.conf.tpl, pass as env var through docker-compose and container.py. Prevents accidental or malicious VRRP advertisement from claiming the cluster VIP. Closes #91 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 0ab8ce7 commit 9eea2c8

6 files changed

Lines changed: 18 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
* Dependabot updates for `github-actions` and `terraform` ecosystems. (#29)
1616
* CI workflow to build and push service images to GitHub Container Registry on master merge. (#97)
1717
* Pull-first with local build fallback for container images during deployment. (#97)
18+
* VRRP authentication to prevent VIP hijacking from L2 segment. (#91)
1819

1920
### Changed
2021

services/mysql-mgmt/docker_compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ services:
8686
- "VIRTUAL_NETWORK=${VIRTUAL_NETWORK}"
8787
- "STATE=${STATE}"
8888
- "PRIORITY=${PRIORITY}"
89+
- "VRRP_PASSWORD=${VRRP_PASSWORD}"
8990
- "MYSQL_TEST_LOGIN_FILE=/opt/.mylogin.cnf"
9091
volumes:
9192
- "default_generated:/opt/default"

services/mysql-mgmt/keepalived.conf.tpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ vrrp_instance virtual_instance {
1919
advert_int 1
2020
nopreempt
2121
garp_master_delay 2
22+
authentication {
23+
auth_type PASS
24+
auth_pass ${VRRP_PASSWORD}
25+
}
2226
track_script {
2327
status
2428
}

src/container.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,8 @@ def run_mysql_mgmt(
281281
secondary_first_mysql_node: str,
282282
secondary_second_mysql_node: str,
283283
state: str,
284-
priority: str) -> None:
284+
priority: str,
285+
vrrp_password: str = '') -> None:
285286

286287
class MySQLMgmt(ContainerInstance):
287288
# pylint: disable=too-many-arguments
@@ -327,6 +328,7 @@ def setup_env(self) -> None:
327328
os.environ["HEALTHCHECK_RETRIES"] = str(self.healthcheck_retries)
328329
os.environ["STATE"] = state
329330
os.environ["PRIORITY"] = priority
331+
os.environ["VRRP_PASSWORD"] = vrrp_password
330332

331333
def run(self) -> None:
332334
self.setup_env()

src/crypto.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ class OpenSSL:
6363
def generate_mysql_root_password() -> str:
6464
return base64.b64encode(os.urandom(16)).decode('utf-8')
6565

66+
@staticmethod
67+
def generate_vrrp_password() -> str:
68+
return base64.b64encode(os.urandom(6)).decode('utf-8')[:8]
69+
6670
@staticmethod
6771
def generate_mysql_superset_password() -> str:
6872
return "".join(random.choice(string.ascii_lowercase) for _ in range(12))

src/initialize.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ def credentials(self) -> None:
125125
self.mysql_root_password = self.cert_manager.generate_mysql_root_password()
126126
self.mysql_superset_password = self.cert_manager.generate_mysql_superset_password()
127127
self.superset_secret_key = self.cert_manager.generate_superset_secret_key()
128+
self.vrrp_password = self.cert_manager.generate_vrrp_password()
128129
for node in list(itertools.chain(self.mysql_nodes, self.mgmt_nodes)):
129130
node.key = self.cert_manager.generate_private_key()
130131
node.csr = self.cert_manager.generate_csr(f'Superset-Cluster-{node.node}', node.key)
@@ -235,15 +236,17 @@ def start_mysql_mgmt(self, node: remote.RemoteConnection, state: str, priority:
235236
'{secondary_first_mysql_node}', \
236237
'{secondary_second_mysql_node}', \
237238
'{state}', \
238-
'{priority}' \
239+
'{priority}', \
240+
'{vrrp_password}' \
239241
)".format(virtual_ip_address=self.virtual_ip_address,
240242
virtual_network_mask=self.virtual_network_mask,
241243
virtual_network_interface=self.virtual_network_interface,
242244
primary_mysql_node=self.mysql_nodes[0].node,
243245
secondary_first_mysql_node=self.mysql_nodes[1].node,
244246
secondary_second_mysql_node=self.mysql_nodes[2].node,
245247
state=state,
246-
priority=priority)
248+
priority=priority,
249+
vrrp_password=self.vrrp_password)
247250
)
248251

249252
def start_superset(self) -> None:

0 commit comments

Comments
 (0)