Skip to content

Commit

Permalink
Merge pull request #5 from vruello/single_keytab
Browse files Browse the repository at this point in the history
Support for storing multiple GMSAs secrets in a single keytab file
  • Loading branch information
WilliamBruneau authored Sep 21, 2023
2 parents 86ae555 + f3aa025 commit 53395fc
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 5 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Support for storing multiple GMSAs secrets in a single keytab file (#5)

## [0.1.0] - 2023-06-05

Initial commit
1 change: 1 addition & 0 deletions gmsad.conf.sample
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ check_interval = 60
#
# # File where to store the keytab of the gMSA. gmsad needs to
# # have read and write permissions on it.
# # You can use the same destination keytab for multiple gMSAs
# gMSA_keytab = /etc/semoule.keytab
#
# # Mask that contains the encryption types present in the keytab in Windows format.
Expand Down
11 changes: 10 additions & 1 deletion gmsad/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from gmsad.utils import every
from gmsad.gmsa import GMSAState
from gmsad.keytab import Keytab

def run(config: configparser.ConfigParser) -> int:
state = init_state(config)
Expand All @@ -26,8 +27,16 @@ def update_loop(config: configparser.ConfigParser, state: dict) -> None:

def init_state(config: configparser.ConfigParser) -> dict:
state = {}
# It is possible to store the secrets of multiple GMSAs in a single keytab file.
# For this to work, each keytab file must be managed by a single "Keytab" instance.
keytabs = {}
for section in config.sections():
if section == 'gmsad':
continue
state[section] = GMSAState(config[section])
keytab_path = config[section]['gMSA_keytab']
if not keytab_path in keytabs:
keytab = Keytab()
keytab.open(keytab_path)
keytabs[keytab_path] = keytab
state[section] = GMSAState(config[section], keytabs[keytab_path])
return state
5 changes: 2 additions & 3 deletions gmsad/gmsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ class GMSAState:
unchanged_password_date: datetime
keytab: Keytab

def __init__(self, config: configparser.SectionProxy) -> None:
def __init__(self, config: configparser.SectionProxy, keytab: Keytab) -> None:
self.config = config
self.current_password = bytes()
self.previous_password = bytes()
self.keytab = Keytab()
self.keytab.open(self.config['gMSA_keytab'])
self.keytab = keytab
self.query_password_date = datetime.fromtimestamp(0).astimezone()
self.unchanged_password_date = datetime.fromtimestamp(0).astimezone()

Expand Down
3 changes: 2 additions & 1 deletion tests/test_gmsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class TestGMSA(unittest.TestCase):
def setUp(self):
config = configparser.ConfigParser()
config.read_string(SAMPLE_CONFIG)
self.gmsa_state = GMSAState(config["sample"])
keytabs = {}
self.gmsa_state = GMSAState(config["sample"], keytabs)

def test_managedpassword_too_short(self):
blob = bytes([0]*31)
Expand Down

0 comments on commit 53395fc

Please sign in to comment.