Skip to content
This repository was archived by the owner on Jul 24, 2023. It is now read-only.

Commit 301fd1c

Browse files
authored
FIX - support keycloak (#1054)
* FIX - support keycloak * ignoring type error * changing build iamge storage driver * upping version of code-build-image * reverting version of code-build-image
1 parent 85e9aeb commit 301fd1c

File tree

7 files changed

+127
-19
lines changed

7 files changed

+127
-19
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1212

1313
### **Removed**
1414

15+
## **[1.3.1]**
16+
17+
### **Added**
18+
19+
### **Changed**
20+
- FIX - support for SAML authentication
21+
- FIX - updated logoc for AutenticatedGroups to team mappings
22+
- FIX - changed storage-driver for build image and image replicator
23+
### **Removed**
24+
1525
## **[1.3.0]**
1626

1727
### **Added**

cli/aws_orbit/models/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class ManagedNodeGroupManifest:
104104
@dataclass(base_schema=BaseSchema, frozen=True)
105105
class CodeBuildImageManifest(ImageManifest):
106106
repository: Optional[str] = "public.ecr.aws/v3o4w1g6/aws-orbit-workbench/code-build-base"
107-
version: Optional[str] = "1.1.0"
107+
version: Optional[str] = "1.2.0"
108108

109109

110110
@dataclass(base_schema=BaseSchema, frozen=True)

cli/aws_orbit/remote_files/cdk/lambda_sources/cognito_post_authentication/index.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,31 +13,51 @@
1313

1414

1515
def handler(event: Dict[str, Any], context: Optional[Dict[str, Any]]) -> Any:
16-
16+
logger.info("Entering POSTAUTH - index.py and the event is: ")
17+
logger.info(json.dumps(event))
1718
cognito_client = boto3.client("cognito-idp")
1819
lambda_client = boto3.client("lambda")
1920

2021
user_name = cast(str, event.get("userName"))
22+
if "preferred_username" in event["request"]["userAttributes"]:
23+
user_name = event["request"]["userAttributes"]["preferred_username"]
2124
user_email = cast(str, event["request"]["userAttributes"].get("email", "invalid_email"))
2225

2326
validate_email(user_email)
2427

2528
user_pool_id = cast(str, event.get("userPoolId"))
2629

27-
user_groups_info = cognito_client.admin_list_groups_for_user(Username=user_name, UserPoolId=user_pool_id)
28-
# user_groups = [group.get("GroupName").split(f"{orbit_env}-")[1] for group in user_groups_info.get("Groups")]
30+
groups_from_provider = None
31+
user_groups_info = None
32+
# if the groups are provided by the provider, use them
33+
if "custom:groups" in event["request"]["userAttributes"]:
34+
groups_from_provider = str(event["request"]["userAttributes"]["custom:groups"]).strip("][").split(", ")
35+
logger.info(f"Found groups from provider: {groups_from_provider}")
36+
else:
37+
logger.info("Did not find groups from provider, fetching from Cognito")
38+
user_groups_info = cognito_client.admin_list_groups_for_user(Username=user_name, UserPoolId=user_pool_id)
2939

3040
team_info = get_auth_group_from_ssm()
3141

3242
user_groups = []
33-
for group in user_groups_info.get("Groups"):
34-
group_name = group.get("GroupName")
35-
if (f"{orbit_env}-") in group_name:
36-
group_name = group_name.split(f"{orbit_env}-")[1]
43+
if groups_from_provider:
44+
logger.info("Groups_from_provider populated, matching to teams")
45+
for group_name in groups_from_provider:
3746
for team_name in team_info:
3847
if group_name in team_info[team_name]:
3948
g = team_name
4049
user_groups.append(g)
50+
user_groups = list(dict.fromkeys(user_groups))
51+
elif user_groups_info:
52+
logger.info("User_group_info populated, matching to teams")
53+
for group in user_groups_info.get("Groups"):
54+
group_name = group.get("GroupName")
55+
if (f"{orbit_env}-") in group_name:
56+
group_name = group_name.split(f"{orbit_env}-")[1]
57+
for team_name in team_info:
58+
if group_name in team_info[team_name]:
59+
g = team_name
60+
user_groups.append(g)
4161

4262
logger.info("Authenticated successfully:")
4363
logger.info(f"userName: {user_name}, userPoolId: {user_pool_id}, userGroups: {user_groups}")
@@ -50,6 +70,7 @@ def handler(event: Dict[str, Any], context: Optional[Dict[str, Any]]) -> Any:
5070
"user_pool_id": user_pool_id,
5171
"expected_user_namespaces": expected_user_namespaces,
5272
}
73+
logger.info(f"Produced Payload = {payload}")
5374
lambda_client.invoke(
5475
FunctionName=f"orbit-{orbit_env}-post-auth-k8s-manage", InvocationType="Event", Payload=json.dumps(payload)
5576
)

cli/aws_orbit/remote_files/deploy.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,10 @@ def _update_userpool(context: Context) -> None:
274274
f"arn:aws:lambda:{context.region}:{context.account_id}:function:orbit-{context.name}-post-authentication"
275275
)
276276

277-
cognito_client.update_user_pool(UserPoolId=context.user_pool_id, LambdaConfig={"PostAuthentication": function_arn})
277+
cognito_client.update_user_pool(
278+
UserPoolId=context.user_pool_id,
279+
LambdaConfig={"PostAuthentication": function_arn, "PostConfirmation": function_arn},
280+
)
278281

279282

280283
def _update_userpool_client(context: Context) -> None:
@@ -284,6 +287,8 @@ def _update_userpool_client(context: Context) -> None:
284287
ClientId=context.user_pool_client_id,
285288
CallbackURLs=[
286289
f"{context.landing_page_url}/oauth2/idpresponse",
290+
f"{context.landing_page_url}/orbit/login",
291+
f"{context.landing_page_url}/saml2/idpresponse",
287292
],
288293
LogoutURLs=[
289294
f"{context.landing_page_url}/orbit/logout",

cli/aws_orbit/services/codebuild.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ def generate_spec(
245245
install = [
246246
(
247247
"nohup /usr/sbin/dockerd --host=unix:///var/run/docker.sock"
248-
" --host=tcp://0.0.0.0:2375 --storage-driver=overlay&"
248+
" --host=tcp://127.0.0.1:2375 --storage-driver=vfs&"
249249
),
250250
'timeout 15 sh -c "until docker info; do echo .; sleep 1; done"',
251251
]

images/orbit-controller/src/orbit_controller/home.py

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
import json
1818
import logging
1919
import os
20+
import re
2021
import time
2122
from typing import Any, Dict, List, Optional, Tuple, Union, cast
2223
from urllib.parse import urlencode, urlparse
2324

25+
import boto3
2426
import requests
2527
from flask import Flask, jsonify, render_template, request
2628
from jose import jwk, jwt
@@ -33,7 +35,7 @@
3335

3436
def is_ready(logger: logging.Logger, app: Flask) -> Any:
3537
logger.debug("cookies: %s", json.dumps(request.cookies))
36-
email, username = _get_user_info_from_jwt(logger)
38+
email, username, groups = _get_user_info_from_jwt(logger)
3739

3840
ready = _is_profile_ready_for_user(logger, username, email)
3941
logger.debug("username: %s, email: %s", username, email)
@@ -42,11 +44,18 @@ def is_ready(logger: logging.Logger, app: Flask) -> Any:
4244

4345
def login(logger: logging.Logger, app: Flask) -> Any:
4446
logger.debug("cookies: %s", json.dumps(request.cookies))
45-
email, username = _get_user_info_from_jwt(logger)
46-
logger.debug("username: %s, email: %s", username, email)
47+
email, username, groups = _get_user_info_from_jwt(logger)
4748

48-
groups = _get_user_groups_from_jwt(logger)
49+
# If we have groups, then the provider sent them.
50+
# Match them to the proper user groups
51+
if groups is not None:
52+
logger.info("We got groups in the auth payload, we need to align them to teams")
53+
user_groups = _get_user_groups_from_provider(logger, list(groups))
54+
else:
55+
logger.info("No groups in auth payload, we are fetchng the from the Cognito User Pool")
56+
user_groups = _get_user_groups_from_jwt(logger)
4957

58+
logger.debug("username: %s, email: %s, groups: %s", username, email, user_groups)
5059
ready = _is_profile_ready_for_user(logger, username, email)
5160
logger.debug("user space is READY? %s", ready)
5261

@@ -60,7 +69,7 @@ def login(logger: logging.Logger, app: Flask) -> Any:
6069
logout_uri=logout_uri,
6170
client_id=client_id,
6271
cognito_domain=cognito_domain,
63-
teams=groups,
72+
teams=user_groups,
6473
env_name=env_name,
6574
)
6675

@@ -105,7 +114,7 @@ def _get_kf_profiles(client: dynamic.DynamicClient) -> List[Dict[str, Any]]:
105114

106115

107116
# https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-authenticate-users.html
108-
def _get_user_info_from_jwt(logger: logging.Logger) -> Tuple[str, str]:
117+
def _get_user_info_from_jwt(logger: logging.Logger) -> Tuple[Any, Any, Optional[Any]]:
109118
logger.debug("headers: %s", json.dumps(dict(request.headers)))
110119
encoded_jwt = request.headers["x-amzn-oidc-data"]
111120
logger.debug("encoded_jwt 'x-amzn-oidc-data':\n %s", encoded_jwt)
@@ -122,9 +131,32 @@ def _get_user_info_from_jwt(logger: logging.Logger) -> Tuple[str, str]:
122131
# Step 3: Get the payload
123132
payload = jwt.decode(encoded_jwt, pub_key, algorithms=["ES256"])
124133
logger.debug("payload:\n %s", payload)
134+
125135
username = payload["username"]
136+
if "preferred_username" in payload:
137+
username = payload["preferred_username"]
138+
126139
email = payload["email"]
127-
return email, username
140+
141+
groups = None
142+
if "custom:groups" in payload:
143+
groups = payload["custom:groups"].strip("][").split(", ")
144+
145+
return email, username, groups
146+
147+
148+
def _get_user_groups_from_provider(logger: logging.Logger, groups_from_provider: List[Any]) -> List[str]:
149+
logger.info("Starting to get groups")
150+
team_info = _get_auth_group_from_ssm(logger)
151+
user_groups = []
152+
for group_name in groups_from_provider:
153+
for team_name in team_info:
154+
if group_name in team_info[team_name]:
155+
g = team_name
156+
user_groups.append(g)
157+
user_groups = list(dict.fromkeys(user_groups))
158+
logger.info(f"User Groups: {user_groups}")
159+
return user_groups
128160

129161

130162
def _get_user_groups_from_jwt(logger: logging.Logger) -> List[str]:
@@ -133,7 +165,22 @@ def _get_user_groups_from_jwt(logger: logging.Logger) -> List[str]:
133165
logger.debug("encoded_jwt 'X-Amzn-Oidc-Accesstoken':\n %s", encoded_jwt)
134166
claims = get_claims(logger, encoded_jwt)
135167
groups: Union[List[Any], str, int] = claims["cognito:groups"] if "cognito:groups" in claims else []
136-
return cast(List[str], groups)
168+
logger.debug(f"Groups from Cognito : {groups}")
169+
team_info = _get_auth_group_from_ssm(logger)
170+
orbit_env = os.environ["ENV_NAME"]
171+
user_groups = []
172+
for group_name in groups: # type: ignore
173+
if (f"{orbit_env}-") in group_name:
174+
group_name = group_name.split(f"{orbit_env}-")[1]
175+
for team_name in team_info:
176+
logger.debug(
177+
f"Team Name: {team_name} group_name: {group_name} team_info[team_name] :{team_info[team_name]} "
178+
)
179+
if group_name in team_info[team_name]:
180+
g = team_name
181+
user_groups.append(g)
182+
logger.info(f"User Groups: {user_groups}")
183+
return user_groups
137184

138185

139186
def _get_keys(logger: logging.Logger) -> List[Dict[str, str]]:
@@ -178,3 +225,28 @@ def get_claims(logger: logging.Logger, token: str) -> Dict[str, Union[str, int]]
178225
logger.debug("claims: %s", claims)
179226

180227
return cast(Dict[str, Union[str, int]], claims)
228+
229+
230+
def _get_auth_group_from_ssm(logger: logging.Logger) -> Dict[str, List[str]]:
231+
ssm_client = boto3.client("ssm")
232+
233+
team_info = {}
234+
orbit_env = os.environ["ENV_NAME"]
235+
236+
team_manifest_pattern = re.compile(rf"/orbit/{orbit_env}/teams/.*/manifest")
237+
238+
paginator = ssm_client.get_paginator("describe_parameters")
239+
page_iterator = paginator.paginate()
240+
241+
for page in page_iterator:
242+
for path in page.get("Parameters"):
243+
param = path.get("Name")
244+
245+
if team_manifest_pattern.fullmatch(param):
246+
param_value = json.loads(ssm_client.get_parameter(Name=param).get("Parameter").get("Value"))
247+
team = param.split("/")[-2]
248+
auth_group_val = param_value.get("AuthenticationGroups")
249+
team_info[team] = auth_group_val
250+
251+
logger.info(f"Team Info fetch: {team_info}")
252+
return team_info

images/orbit-controller/src/orbit_controller/utils/imagereplication_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def _generate_buildspec(repo_host: str, repo_prefix: str, src: str, dest: str) -
3434
"commands": [
3535
(
3636
"nohup /usr/sbin/dockerd --host=unix:///var/run/docker.sock "
37-
"--host=tcp://0.0.0.0:2375 --storage-driver=overlay&"
37+
"--host=tcp://127.0.0.1:2375 --storage-driver=vfs&"
3838
),
3939
'timeout 15 sh -c "until docker info; do echo .; sleep 1; done"',
4040
],

0 commit comments

Comments
 (0)