Skip to content

Commit

Permalink
Merge pull request #159 from TeskaLabs/fix/batman-elk-sync
Browse files Browse the repository at this point in the history
Fix the synchronization of ELK roles under batman
  • Loading branch information
byewokko authored Feb 23, 2023
2 parents b0a1752 + 0fe5fc6 commit d98e2a3
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 36 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Fix sync method in Batman module (3c68cb8, PLUM Sprint 230210)
- Fix cookie client session flow (#155, PLUM Sprint 230210)
- Renaming resources without description (#158, PLUM Sprint 230210)
- Batman does not add nonexistent roles to Kibana users (#159, PLUM Sprint 230210)

### Features
- Allow unsetting some client features (#148, PLUM Sprint 230113)
Expand Down
63 changes: 27 additions & 36 deletions seacatauth/batman/elk.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,22 @@ class ELKIntegration(asab.config.Configurable):
"""

ConfigDefaults = {
'url': 'http://localhost:9200/',
'username': 'elastic',
'password': 'elastic',
"url": "http://localhost:9200/",
"username": "elastic",
"password": "elastic",

'local_users': 'elastic kibana logstash_system beats_system remote_monitoring_user',

'mapped_roles_prefixes': '*/elk:', # Prefix of roles that will be transfered to Kibana
# List of elasticsearch system users
# If Seacat Auth has users with one of these usernames, it will not sync them
# to avoid interfering with kibana system users
"local_users": "elastic kibana logstash_system beats_system remote_monitoring_user",

# Resources with this prefix will be mapped to Kibana users as roles
# E.g.: Resource "elk:kibana-analyst" will be mapped to role "kibana-analyst"
"resource_prefix": "elk:",

'managed_role': 'seacat_managed', # 'flags' users in ElasticSearch/Kibana that is managed by us,
# This role 'flags' users in ElasticSearch/Kibana that is managed by Seacat Auth
# There should be a role created in the ElasticSearch that grants no rights
"seacat_user_flag": "seacat_managed",
}


Expand All @@ -50,22 +52,18 @@ def __init__(self, batman_svc, config_section_name="batman:elk", config=None):
self.RoleService = self.BatmanService.App.get_service("seacatauth.RoleService")
self.ResourceService = self.BatmanService.App.get_service("seacatauth.ResourceService")

username = self.Config.get('username')
password = self.Config.get('password')
username = self.Config.get("username")
password = self.Config.get("password")
self.BasicAuth = aiohttp.BasicAuth(username, password)

self.URL = self.Config.get('url').rstrip('/')
self.URL = self.Config.get("url").rstrip("/")
self.ResourcePrefix = self.Config.get("resource_prefix")
self.ELKResourceRegex = re.compile("^{}".format(
re.escape(self.Config.get("resource_prefix"))
))
self.ELKSeacatFlagRole = self.Config.get("managed_role")

# TODO: Obsolete, back compat only. Use resources instead of roles.
#
self.RolePrefixes = re.split(r"\s+", self.Config.get("mapped_roles_prefixes"))
self.ELKSeacatFlagRole = self.Config.get("seacat_user_flag")

lu = re.split(r'\s+', self.Config.get('local_users'), flags=re.MULTILINE)
lu = re.split(r"\s+", self.Config.get("local_users"), flags=re.MULTILINE)
lu.append(username)

self.LocalUsers = frozenset(lu)
Expand All @@ -81,6 +79,7 @@ async def initialize(self):
await self.sync_all()

async def _initialize_resources(self):
# TODO: Remove resource if its respective kibana role has been removed
"""
Fetches roles from ELK and creates a Seacat Auth resource for each one of them.
"""
Expand Down Expand Up @@ -110,7 +109,7 @@ async def _initialize_resources(self):
if resource_id not in existing_elk_resources:
await self.ResourceService.create(
resource_id,
description="Grants access to ELK role '{}.".format(role)
description="Grants access to ELK role {!r}.".format(role)
)

async def sync_all(self):
Expand All @@ -124,7 +123,7 @@ async def sync_all(self):


async def sync(self, cred: dict, elk_resources: typing.Iterable):
username = cred.get('username')
username = cred.get("username")
if username is None:
# Be defensive
L.info("Cannot create user: No username", struct_data={"cid": cred["_id"]})
Expand All @@ -135,29 +134,27 @@ async def sync(self, cred: dict, elk_resources: typing.Iterable):
return

json = {
'enabled': cred.get('suspended', False) is not True,
"enabled": cred.get("suspended", False) is not True,

# Generate technical password
'password': self.BatmanService.generate_password(cred['_id']),
"password": self.BatmanService.generate_password(cred["_id"]),

'metadata': {
"metadata": {
# We are managed by SeaCat Auth
'seacatauth': True
"seacatauth": True
},

}

v = cred.get('email')
v = cred.get("email")
if v is not None:
json['email'] = v
json["email"] = v

v = cred.get('full_name')
v = cred.get("full_name")
if v is not None:
json['full_name'] = v
json["full_name"] = v

elk_roles = set(
self.ELKSeacatFlagRole, # Add a role that marks users managed by Seacat Auth
)
elk_roles = {self.ELKSeacatFlagRole} # Add a role that marks users managed by Seacat Auth

# Get authz dict
authz = await build_credentials_authz(self.TenantService, self.RoleService, cred["_id"])
Expand All @@ -176,17 +173,11 @@ async def sync(self, cred: dict, elk_resources: typing.Iterable):
for resource in user_resources.intersection(elk_resources)
)

# ELK roles from tenants
for tenant in authz:
if tenant == "*":
continue
elk_roles.add("tenant_{}".format(tenant))

json["roles"] = list(elk_roles)

try:
async with aiohttp.ClientSession(auth=self.BasicAuth) as session:
async with session.post('{}/_xpack/security/user/{}'.format(self.URL, username), json=json) as resp:
async with session.post("{}/_xpack/security/user/{}".format(self.URL, username), json=json) as resp:
if resp.status == 200:
# Everything is alright here
pass
Expand Down

0 comments on commit d98e2a3

Please sign in to comment.