From 803e6aa8b95b1f0188e74d8965d78048d5cc5a50 Mon Sep 17 00:00:00 2001 From: Nikki <17799906+nikki-t@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:00:44 -0400 Subject: [PATCH 1/9] Initial Airflow Cognito integration --- airflow/config/webserver_config.py | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 airflow/config/webserver_config.py diff --git a/airflow/config/webserver_config.py b/airflow/config/webserver_config.py new file mode 100644 index 00000000..a9c5c68c --- /dev/null +++ b/airflow/config/webserver_config.py @@ -0,0 +1,56 @@ +import os +from typing import Any, Dict + +# from airflow.auth.managers.fab.security_manager.override import FabAirflowSecurityManagerOverride +from airflow.providers.fab.auth_manager.security_manager.override import FabAirflowSecurityManagerOverride # Based on warning when launching airflow webserver +from flask_appbuilder.security.manager import AUTH_OAUTH + +# Cognito integration data +COGNITO_BASE_URL = os.environ["COGNITO_BASE_URL"] +COGNITO_CLIENT_ID = os.environ["COGNITO_CLIENT_ID"] +COGNITO_CLIENT_SECRET = os.environ["COGNITO_CLIENT_SECRET"] + +# Authentication constants +AUTH_TYPE = AUTH_OAUTH +AUTH_USER_REGISTRATION = True # allow users not in the FAB DB +AUTH_USER_REGISTRATION_ROLE = "Public" # role given in addition to AUTH_ROLES +AUTH_ROLES_SYNC_AT_LOGIN = False # replace all user's roles each login +AUTH_ROLES_MAPPING = { # mapping of FAB roles to userinfo["role_keys"] + "Unity_Viewer": ["User"], + "Unity_Admin": ["Admin"], +} + +# Cognito provider data +OAUTH_PROVIDERS = [ + { + "name": "Cognito", + "icon": "fa-amazon", + "token_key": "access_token", + "remote_app": { + "client_id": COGNITO_CLIENT_ID, + "client_secret": COGNITO_CLIENT_SECRET, + "api_base_url": f"{COGNITO_BASE_URL}/", + "client_kwargs": {"scope": "email openid profile"}, + "access_token_url": f"{COGNITO_BASE_URL}/token", + "authorize_url": f"{COGNITO_BASE_URL}/authorize", + } + } +] + +# Security manager override +class CognitoAuthorizer(FabAirflowSecurityManagerOverride): + + def get_oauth_user_info(self, provider: str, resp: dict[str, Any]) -> dict[str, Any]: + + if provider == "Cognito": + me = self.appbuilder.sm.oauth_remotes[provider].get("userInfo") + print(me) + return { + "username": "admin", + "email": "admin@test.airflow.com", + "first_name": "Admin", + "last_name": "Admin", + "role_keys": ["Admin"] + } + +SECURITY_MANAGER_CLASS = CognitoAuthorizer \ No newline at end of file From 13483cdce09d15bfdad85ecd0b6dff0c7cfba15f Mon Sep 17 00:00:00 2001 From: Nikki <17799906+nikki-t@users.noreply.github.com> Date: Mon, 7 Oct 2024 11:40:38 -0400 Subject: [PATCH 2/9] Updated webserver config file that includes new overrides --- airflow/config/webserver_config.py | 122 ++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 21 deletions(-) diff --git a/airflow/config/webserver_config.py b/airflow/config/webserver_config.py index a9c5c68c..ea08b680 100644 --- a/airflow/config/webserver_config.py +++ b/airflow/config/webserver_config.py @@ -1,23 +1,34 @@ +import base64 +import json +import logging import os -from typing import Any, Dict +from typing import Any -# from airflow.auth.managers.fab.security_manager.override import FabAirflowSecurityManagerOverride -from airflow.providers.fab.auth_manager.security_manager.override import FabAirflowSecurityManagerOverride # Based on warning when launching airflow webserver +from airflow.providers.fab.auth_manager.security_manager.override import FabAirflowSecurityManagerOverride +from authlib.common.urls import url_decode +from authlib.integrations.base_client.sync_openid import OpenIDMixin +from authlib.oauth2.client import OAuth2Client from flask_appbuilder.security.manager import AUTH_OAUTH +from tornado.httpclient import HTTPClient, HTTPRequest +from tornado.httputil import url_concat + +# Logging +log = logging.getLogger("flask_appbuilder.security.views") # Cognito integration data COGNITO_BASE_URL = os.environ["COGNITO_BASE_URL"] COGNITO_CLIENT_ID = os.environ["COGNITO_CLIENT_ID"] COGNITO_CLIENT_SECRET = os.environ["COGNITO_CLIENT_SECRET"] +COGNITO_USER_POOL_ID = os.environ["COGNITO_USER_POOL_ID"] # Authentication constants AUTH_TYPE = AUTH_OAUTH -AUTH_USER_REGISTRATION = True # allow users not in the FAB DB -AUTH_USER_REGISTRATION_ROLE = "Public" # role given in addition to AUTH_ROLES -AUTH_ROLES_SYNC_AT_LOGIN = False # replace all user's roles each login -AUTH_ROLES_MAPPING = { # mapping of FAB roles to userinfo["role_keys"] - "Unity_Viewer": ["User"], - "Unity_Admin": ["Admin"], +AUTH_USER_REGISTRATION = True # allow users not in the FAB DB +AUTH_USER_REGISTRATION_ROLE = "Admin" # role given in addition to AUTH_ROLES +AUTH_ROLES_SYNC_AT_LOGIN = True # replace all user's roles each login +AUTH_ROLES_MAPPING = { # mapping of Cognito groups to FAB roles + "Unity_Viewer": "User", + "Unity_Admin": "Admin", } # Cognito provider data @@ -33,24 +44,93 @@ "client_kwargs": {"scope": "email openid profile"}, "access_token_url": f"{COGNITO_BASE_URL}/token", "authorize_url": f"{COGNITO_BASE_URL}/authorize", - } + "jwks_uri": f"https://cognito-idp.us-west-2.amazonaws.com/{COGNITO_USER_POOL_ID}/.well-known/jwks.json", + }, } ] + +def fetch_token(self, url, body="", headers=None, auth=None, method="POST", state=None, **kwargs): + """Overridden method to fetch Cognito token data.""" + + # Encode client Id and secret + message = auth.client_id + ":" + auth.client_secret + message_bytes = message.encode("ascii") + base64_bytes = base64.b64encode(message_bytes) + base64_auth = base64_bytes.decode("ascii") + + # Build URL with parameters + body_dict = dict(url_decode(body)) + params = dict( + client_id=auth.client_id, + code=body_dict["code"], + grant_type="authorization_code", + redirect_uri=body_dict["redirect_uri"], + ) + url = url_concat(url, params) + req = HTTPRequest( + url, + method="POST", + headers={ + "Accept": "application/json", + "Authorization": "Basic " + base64_auth, + "Content-Type": "application/x-www-form-urlencoded", + }, + body="", + ) + + # POST request to Cognito for token data + http_client = HTTPClient() + resp = http_client.fetch(req) + resp_json = json.loads(resp.body.decode("utf8", "replace")) + + return resp_json + + +def fetch_jwk(self, force=False): + """Fetch JWK public data.""" + + metadata = self.load_server_metadata() + jwks_uri = metadata.get("jwks_uri") + log.debug("jwks_uri: %s", jwks_uri) + + req = HTTPRequest(jwks_uri, method="GET") + http_client = HTTPClient() + jwks_response = http_client.fetch(req) + jwks_json = json.loads(jwks_response.body.decode("utf8", "replace")) + log.debug("jwks_json: %s", jwks_json) + return jwks_json + + +def map_roles(roles): + """Map Cognito roles to Airflow roles.""" + + log.debug("ROLES: %s", roles) + + return list(set(AUTH_ROLES_MAPPING.get(role, "Public") for role in roles)) + + # Security manager override class CognitoAuthorizer(FabAirflowSecurityManagerOverride): - + def get_oauth_user_info(self, provider: str, resp: dict[str, Any]) -> dict[str, Any]: - + """Override method to login with Cognito specific data.""" + if provider == "Cognito": - me = self.appbuilder.sm.oauth_remotes[provider].get("userInfo") - print(me) + user_info = resp["userinfo"] + log.debug("user_info: %s", user_info) + + roles = map_roles(user_info["cognito:groups"]) + log.debug("roles: %s", roles) + return { - "username": "admin", - "email": "admin@test.airflow.com", - "first_name": "Admin", - "last_name": "Admin", - "role_keys": ["Admin"] + "username": user_info["cognito:username"], + "email": user_info["email"], + "role_keys": roles, } - -SECURITY_MANAGER_CLASS = CognitoAuthorizer \ No newline at end of file + + +# Overrides +SECURITY_MANAGER_CLASS = CognitoAuthorizer +OAuth2Client._fetch_token = fetch_token +OpenIDMixin.fetch_jwk_set = fetch_jwk From a7268f37ec328da537f47d413ac616a63ed2fa12 Mon Sep 17 00:00:00 2001 From: Nikki <17799906+nikki-t@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:44:16 -0400 Subject: [PATCH 3/9] Remove debug logging of user roles --- airflow/config/webserver_config.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/airflow/config/webserver_config.py b/airflow/config/webserver_config.py index ea08b680..f6e86e08 100644 --- a/airflow/config/webserver_config.py +++ b/airflow/config/webserver_config.py @@ -105,8 +105,6 @@ def fetch_jwk(self, force=False): def map_roles(roles): """Map Cognito roles to Airflow roles.""" - log.debug("ROLES: %s", roles) - return list(set(AUTH_ROLES_MAPPING.get(role, "Public") for role in roles)) From 14ce7bb3717c351eef2007f492efe1c86b372f8f Mon Sep 17 00:00:00 2001 From: Nikki <17799906+nikki-t@users.noreply.github.com> Date: Fri, 11 Oct 2024 08:01:33 -0400 Subject: [PATCH 4/9] Integrate Cognito with Airflow FAB authentication --- airflow/helm/values.tmpl.yaml | 11 ++++++++++ terraform-unity/main.tf | 4 ++++ .../terraform-unity-sps-airflow/main.tf | 5 +++++ .../terraform-unity-sps-airflow/variables.tf | 20 +++++++++++++++++++ terraform-unity/variables.tf | 20 +++++++++++++++++++ 5 files changed, 60 insertions(+) diff --git a/airflow/helm/values.tmpl.yaml b/airflow/helm/values.tmpl.yaml index 449b57a2..58610cb8 100644 --- a/airflow/helm/values.tmpl.yaml +++ b/airflow/helm/values.tmpl.yaml @@ -130,6 +130,9 @@ webserverSecretKeySecretName: ${webserver_secret_name} webserver: replicas: 3 + webserverConfig: |- + ${webserver_config} + startupProbe: timeoutSeconds: 20 failureThreshold: 60 # Number of tries before giving up (10 minutes with periodSeconds of 10) @@ -275,6 +278,14 @@ env: value: "${karpenter_node_pools}" - name: "AIRFLOW_VAR_ECR_URI" value: "${cwl_dag_ecr_uri}" + - name: "COGNITO_CLIENT_ID" + value: "${cognito_client_id}" + - name: "COGNITO_CLIENT_SECRET" + value: "${cognito_client_secret}" + - name: "COGNITO_BASE_URL" + value: "${cognito_base_url}" + - name: "COGNITO_USER_POOL_ID" + value: "${cognito_user_pool_id}" # https://airflow.apache.org/docs/apache-airflow/stable/administration-and-deployment/security/api.html extraEnv: | diff --git a/terraform-unity/main.tf b/terraform-unity/main.tf index 6b816d47..0260c614 100644 --- a/terraform-unity/main.tf +++ b/terraform-unity/main.tf @@ -58,6 +58,10 @@ module "unity-sps-airflow" { docker_images = var.airflow_docker_images helm_charts = var.helm_charts karpenter_node_pools = module.unity-sps-karpenter-node-config.karpenter_node_pools + cognito_client_id = var.cognito_client_id + cognito_client_secret = var.cognito_client_secret + cognito_base_url = var.cognito_base_url + cognito_user_pool_id = var.cognito_user_pool_id } module "unity-sps-ogc-processes-api" { diff --git a/terraform-unity/modules/terraform-unity-sps-airflow/main.tf b/terraform-unity/modules/terraform-unity-sps-airflow/main.tf index 1c9ef2d5..0c7c2693 100644 --- a/terraform-unity/modules/terraform-unity-sps-airflow/main.tf +++ b/terraform-unity/modules/terraform-unity-sps-airflow/main.tf @@ -385,6 +385,11 @@ resource "helm_release" "airflow" { unity_cluster_name = data.aws_eks_cluster.cluster.name karpenter_node_pools = join(",", var.karpenter_node_pools) cwl_dag_ecr_uri = "${data.aws_caller_identity.current.account_id}.dkr.ecr.us-west-2.amazonaws.com" + webserver_config = indent(4, file("${path.module}/../../../airflow/config/webserver_config.py")) + cognito_client_id = var.cognito_client_id + cognito_client_secret = var.cognito_client_secret + cognito_base_url = var.cognito_base_url + cognito_user_pool_id = var.cognito_user_pool_id }) ] set_sensitive { diff --git a/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf b/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf index 3f6ff754..9cbd7b73 100644 --- a/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf +++ b/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf @@ -76,3 +76,23 @@ variable "karpenter_node_pools" { description = "Names of the Karpenter node pools" type = list(string) } + +variable "cognito_client_id" { + description = "Cognito user pool client id for application." + type = string +} + +variable "cognito_client_secret" { + description = "Cognito user pool client secret for application." + type = string +} + +variable "cognito_base_url" { + description = "Cognito user pool URL." + type = string +} + +variable "cognito_user_pool_id" { + description = "Cognito user pool id." + type = string +} \ No newline at end of file diff --git a/terraform-unity/variables.tf b/terraform-unity/variables.tf index eed6e71a..cb433c76 100644 --- a/terraform-unity/variables.tf +++ b/terraform-unity/variables.tf @@ -339,3 +339,23 @@ variable "dag_catalog_repo" { dags_directory_path = "airflow/dags" } } + +variable "cognito_client_id" { + description = "Cognito user pool client id for application." + type = string +} + +variable "cognito_client_secret" { + description = "Cognito user pool client secret for application." + type = string +} + +variable "cognito_base_url" { + description = "Cognito user pool URL." + type = string +} + +variable "cognito_user_pool_id" { + description = "Cognito user pool id." + type = string +} \ No newline at end of file From a524031b8ced1c317c75a9437d0b36e73c57bd6e Mon Sep 17 00:00:00 2001 From: Nikki <17799906+nikki-t@users.noreply.github.com> Date: Fri, 11 Oct 2024 08:41:37 -0400 Subject: [PATCH 5/9] Enable SSL on SPS load balancers --- terraform-unity/.terraform.lock.hcl | 26 +++++++++---------- .../terraform-unity-sps-airflow/data.tf | 4 +++ .../terraform-unity-sps-airflow/main.tf | 20 ++++++++------ .../data.tf | 4 +++ .../main.tf | 16 +++++++----- 5 files changed, 43 insertions(+), 27 deletions(-) diff --git a/terraform-unity/.terraform.lock.hcl b/terraform-unity/.terraform.lock.hcl index 8ef7a4f8..b1edf5d2 100644 --- a/terraform-unity/.terraform.lock.hcl +++ b/terraform-unity/.terraform.lock.hcl @@ -65,22 +65,22 @@ provider "registry.terraform.io/hashicorp/kubernetes" { } provider "registry.terraform.io/hashicorp/local" { - version = "2.5.1" + version = "2.5.2" constraints = ">= 2.5.1" hashes = [ - "h1:/GAVA/xheGQcbOZEq0qxANOg+KVLCA7Wv8qluxhTjhU=", - "zh:0af29ce2b7b5712319bf6424cb58d13b852bf9a777011a545fac99c7fdcdf561", - "zh:126063ea0d79dad1f68fa4e4d556793c0108ce278034f101d1dbbb2463924561", - "zh:196bfb49086f22fd4db46033e01655b0e5e036a5582d250412cc690fa7995de5", - "zh:37c92ec084d059d37d6cffdb683ccf68e3a5f8d2eb69dd73c8e43ad003ef8d24", - "zh:4269f01a98513651ad66763c16b268f4c2da76cc892ccfd54b401fff6cc11667", - "zh:51904350b9c728f963eef0c28f1d43e73d010333133eb7f30999a8fb6a0cc3d8", - "zh:73a66611359b83d0c3fcba2984610273f7954002febb8a57242bbb86d967b635", + "h1:IyFbOIO6mhikFNL/2h1iZJ6kyN3U00jgkpCLUCThAfE=", + "zh:136299545178ce281c56f36965bf91c35407c11897f7082b3b983d86cb79b511", + "zh:3b4486858aa9cb8163378722b642c57c529b6c64bfbfc9461d940a84cd66ebea", + "zh:4855ee628ead847741aa4f4fc9bed50cfdbf197f2912775dd9fe7bc43fa077c0", + "zh:4b8cd2583d1edcac4011caafe8afb7a95e8110a607a1d5fb87d921178074a69b", + "zh:52084ddaff8c8cd3f9e7bcb7ce4dc1eab00602912c96da43c29b4762dc376038", + "zh:71562d330d3f92d79b2952ffdda0dad167e952e46200c767dd30c6af8d7c0ed3", "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:7ae387993a92bcc379063229b3cce8af7eaf082dd9306598fcd42352994d2de0", - "zh:9e0f365f807b088646db6e4a8d4b188129d9ebdbcf2568c8ab33bddd1b82c867", - "zh:b5263acbd8ae51c9cbffa79743fbcadcb7908057c87eb22fd9048268056efbc4", - "zh:dfcd88ac5f13c0d04e24be00b686d069b4879cc4add1b7b1a8ae545783d97520", + "zh:805f81ade06ff68fa8b908d31892eaed5c180ae031c77ad35f82cb7a74b97cf4", + "zh:8b6b3ebeaaa8e38dd04e56996abe80db9be6f4c1df75ac3cccc77642899bd464", + "zh:ad07750576b99248037b897de71113cc19b1a8d0bc235eb99173cc83d0de3b1b", + "zh:b9f1c3bfadb74068f5c205292badb0661e17ac05eb23bfe8bd809691e4583d0e", + "zh:cc4cbcd67414fefb111c1bf7ab0bc4beb8c0b553d01719ad17de9a047adff4d1", ] } diff --git a/terraform-unity/modules/terraform-unity-sps-airflow/data.tf b/terraform-unity/modules/terraform-unity-sps-airflow/data.tf index eb80736a..2e136b5a 100644 --- a/terraform-unity/modules/terraform-unity-sps-airflow/data.tf +++ b/terraform-unity/modules/terraform-unity-sps-airflow/data.tf @@ -43,3 +43,7 @@ data "aws_secretsmanager_secret_version" "db" { data "aws_efs_file_system" "efs" { file_system_id = var.efs_file_system_id } + +data "aws_ssm_parameter" "ssl_cert_arn" { + name = "/unity/account/network/ssl" +} diff --git a/terraform-unity/modules/terraform-unity-sps-airflow/main.tf b/terraform-unity/modules/terraform-unity-sps-airflow/main.tf index 0c7c2693..07cbeaa4 100644 --- a/terraform-unity/modules/terraform-unity-sps-airflow/main.tf +++ b/terraform-unity/modules/terraform-unity-sps-airflow/main.tf @@ -469,10 +469,12 @@ resource "kubernetes_ingress_v1" "airflow_ingress" { "alb.ingress.kubernetes.io/scheme" = "internet-facing" "alb.ingress.kubernetes.io/target-type" = "ip" "alb.ingress.kubernetes.io/subnets" = join(",", jsondecode(data.aws_ssm_parameter.subnet_ids.value)["public"]) - "alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTP\": ${local.load_balancer_port}}]" + "alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTPS\": ${local.load_balancer_port}}]" "alb.ingress.kubernetes.io/security-groups" = aws_security_group.airflow_ingress_sg.id "alb.ingress.kubernetes.io/manage-backend-security-group-rules" = "true" "alb.ingress.kubernetes.io/healthcheck-path" = "/health" + "alb.ingress.kubernetes.io/certificate-arn" = data.aws_ssm_parameter.ssl_cert_arn.value + "alb.ingress.kubernetes.io/ssl-policy" = "ELBSecurityPolicy-TLS13-1-2-2021-06" } } spec { @@ -506,10 +508,12 @@ resource "kubernetes_ingress_v1" "airflow_ingress_internal" { "alb.ingress.kubernetes.io/scheme" = "internal" "alb.ingress.kubernetes.io/target-type" = "ip" "alb.ingress.kubernetes.io/subnets" = join(",", jsondecode(data.aws_ssm_parameter.subnet_ids.value)["private"]) - "alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTP\": ${local.load_balancer_port}}]" + "alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTPS\": ${local.load_balancer_port}}]" "alb.ingress.kubernetes.io/security-groups" = aws_security_group.airflow_ingress_sg_internal.id "alb.ingress.kubernetes.io/manage-backend-security-group-rules" = "true" "alb.ingress.kubernetes.io/healthcheck-path" = "/health" + "alb.ingress.kubernetes.io/certificate-arn" = data.aws_ssm_parameter.ssl_cert_arn.value + "alb.ingress.kubernetes.io/ssl-policy" = "ELBSecurityPolicy-TLS13-1-2-2021-06" } } spec { @@ -539,7 +543,7 @@ resource "aws_ssm_parameter" "airflow_ui_url" { name = format("/%s", join("/", compact(["", var.project, var.venue, var.service_area, "processing", "airflow", "ui_url"]))) description = "The URL of the Airflow UI." type = "String" - value = "http://${data.kubernetes_ingress_v1.airflow_ingress.status[0].load_balancer[0].ingress[0].hostname}:5000" + value = "https://${data.kubernetes_ingress_v1.airflow_ingress.status[0].load_balancer[0].ingress[0].hostname}:5000" tags = merge(local.common_tags, { Name = format(local.resource_name_prefix, "endpoints-airflow_ui") Component = "SSM" @@ -553,8 +557,8 @@ resource "aws_ssm_parameter" "airflow_ui_health_check_endpoint" { type = "String" value = jsonencode({ "componentName" : "Airflow UI" - "healthCheckUrl" : "http://${data.kubernetes_ingress_v1.airflow_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5000/health" - "landingPageUrl" : "http://${data.kubernetes_ingress_v1.airflow_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5000" + "healthCheckUrl" : "https://${data.kubernetes_ingress_v1.airflow_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5000/health" + "landingPageUrl" : "https://${data.kubernetes_ingress_v1.airflow_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5000" }) tags = merge(local.common_tags, { Name = format(local.resource_name_prefix, "health-check-endpoints-airflow_ui") @@ -570,7 +574,7 @@ resource "aws_ssm_parameter" "airflow_api_url" { name = format("/%s", join("/", compact(["", var.project, var.venue, var.service_area, "processing", "airflow", "api_url"]))) description = "The URL of the Airflow REST API." type = "String" - value = "http://${data.kubernetes_ingress_v1.airflow_ingress.status[0].load_balancer[0].ingress[0].hostname}:5000/api/v1" + value = "https://${data.kubernetes_ingress_v1.airflow_ingress.status[0].load_balancer[0].ingress[0].hostname}:5000/api/v1" tags = merge(local.common_tags, { Name = format(local.resource_name_prefix, "endpoints-airflow_api") Component = "SSM" @@ -584,8 +588,8 @@ resource "aws_ssm_parameter" "airflow_api_health_check_endpoint" { type = "String" value = jsonencode({ "componentName" : "Airflow API" - "healthCheckUrl" : "http://${data.kubernetes_ingress_v1.airflow_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5000/api/v1/health" - "landingPageUrl" : "http://${data.kubernetes_ingress_v1.airflow_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5000/api/v1" + "healthCheckUrl" : "https://${data.kubernetes_ingress_v1.airflow_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5000/api/v1/health" + "landingPageUrl" : "https://${data.kubernetes_ingress_v1.airflow_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5000/api/v1" }) tags = merge(local.common_tags, { Name = format(local.resource_name_prefix, "health-check-endpoints-airflow_api") diff --git a/terraform-unity/modules/terraform-unity-sps-ogc-processes-api/data.tf b/terraform-unity/modules/terraform-unity-sps-ogc-processes-api/data.tf index 532e57f5..d76a7e60 100644 --- a/terraform-unity/modules/terraform-unity-sps-ogc-processes-api/data.tf +++ b/terraform-unity/modules/terraform-unity-sps-ogc-processes-api/data.tf @@ -43,3 +43,7 @@ data "kubernetes_ingress_v1" "ogc_processes_api_ingress_internal" { namespace = data.kubernetes_namespace.service_area.metadata[0].name } } + +data "aws_ssm_parameter" "ssl_cert_arn" { + name = "/unity/account/network/ssl" +} diff --git a/terraform-unity/modules/terraform-unity-sps-ogc-processes-api/main.tf b/terraform-unity/modules/terraform-unity-sps-ogc-processes-api/main.tf index 41974460..a8b1ed21 100644 --- a/terraform-unity/modules/terraform-unity-sps-ogc-processes-api/main.tf +++ b/terraform-unity/modules/terraform-unity-sps-ogc-processes-api/main.tf @@ -267,10 +267,12 @@ resource "kubernetes_ingress_v1" "ogc_processes_api_ingress" { "alb.ingress.kubernetes.io/scheme" = "internet-facing" "alb.ingress.kubernetes.io/target-type" = "ip" "alb.ingress.kubernetes.io/subnets" = join(",", jsondecode(data.aws_ssm_parameter.subnet_ids.value)["public"]) - "alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTP\": ${local.load_balancer_port}}]" + "alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTPS\": ${local.load_balancer_port}}]" "alb.ingress.kubernetes.io/security-groups" = aws_security_group.ogc_ingress_sg.id "alb.ingress.kubernetes.io/manage-backend-security-group-rules" = "true" "alb.ingress.kubernetes.io/healthcheck-path" = "/health" + "alb.ingress.kubernetes.io/certificate-arn" = data.aws_ssm_parameter.ssl_cert_arn.value + "alb.ingress.kubernetes.io/ssl-policy" = "ELBSecurityPolicy-TLS13-1-2-2021-06" } } spec { @@ -303,10 +305,12 @@ resource "kubernetes_ingress_v1" "ogc_processes_api_ingress_internal" { "alb.ingress.kubernetes.io/scheme" = "internal" "alb.ingress.kubernetes.io/target-type" = "ip" "alb.ingress.kubernetes.io/subnets" = join(",", jsondecode(data.aws_ssm_parameter.subnet_ids.value)["private"]) - "alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTP\": ${local.load_balancer_port}}]" + "alb.ingress.kubernetes.io/listen-ports" = "[{\"HTTPS\": ${local.load_balancer_port}}]" "alb.ingress.kubernetes.io/security-groups" = aws_security_group.ogc_ingress_sg_internal.id "alb.ingress.kubernetes.io/manage-backend-security-group-rules" = "true" "alb.ingress.kubernetes.io/healthcheck-path" = "/health" + "alb.ingress.kubernetes.io/certificate-arn" = data.aws_ssm_parameter.ssl_cert_arn.value + "alb.ingress.kubernetes.io/ssl-policy" = "ELBSecurityPolicy-TLS13-1-2-2021-06" } } spec { @@ -335,7 +339,7 @@ resource "aws_ssm_parameter" "ogc_processes_ui_url" { name = format("/%s", join("/", compact(["", var.project, var.venue, var.service_area, "processing", "ogc_processes", "ui_url"]))) description = "The URL of the OGC Proccesses API Docs UI." type = "String" - value = "http://${data.kubernetes_ingress_v1.ogc_processes_api_ingress.status[0].load_balancer[0].ingress[0].hostname}:5001/redoc" + value = "https://${data.kubernetes_ingress_v1.ogc_processes_api_ingress.status[0].load_balancer[0].ingress[0].hostname}:5001/redoc" tags = merge(local.common_tags, { Name = format(local.resource_name_prefix, "endpoints-ogc_processes_ui") Component = "SSM" @@ -347,7 +351,7 @@ resource "aws_ssm_parameter" "ogc_processes_api_url" { name = format("/%s", join("/", compact(["", var.project, var.venue, var.service_area, "processing", "ogc_processes", "api_url"]))) description = "The URL of the OGC Processes REST API." type = "String" - value = "http://${data.kubernetes_ingress_v1.ogc_processes_api_ingress.status[0].load_balancer[0].ingress[0].hostname}:5001" + value = "https://${data.kubernetes_ingress_v1.ogc_processes_api_ingress.status[0].load_balancer[0].ingress[0].hostname}:5001" tags = merge(local.common_tags, { Name = format(local.resource_name_prefix, "endpoints-ogc_processes_api") Component = "SSM" @@ -361,8 +365,8 @@ resource "aws_ssm_parameter" "ogc_processes_api_health_check_endpoint" { type = "String" value = jsonencode({ "componentName" : "OGC API" - "healthCheckUrl" : "http://${data.kubernetes_ingress_v1.ogc_processes_api_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5001/health" - "landingPageUrl" : "http://${data.kubernetes_ingress_v1.ogc_processes_api_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5001" + "healthCheckUrl" : "https://${data.kubernetes_ingress_v1.ogc_processes_api_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5001/health" + "landingPageUrl" : "https://${data.kubernetes_ingress_v1.ogc_processes_api_ingress_internal.status[0].load_balancer[0].ingress[0].hostname}:5001" }) tags = merge(local.common_tags, { Name = format(local.resource_name_prefix, "health-check-endpoints-ogc_processes_api") From f219f55cd725dd4f56f7aeb514031b9d6d5b9018 Mon Sep 17 00:00:00 2001 From: Nikki <17799906+nikki-t@users.noreply.github.com> Date: Fri, 11 Oct 2024 08:57:26 -0400 Subject: [PATCH 6/9] Add end of file new line --- .../modules/terraform-unity-sps-airflow/variables.tf | 2 +- terraform-unity/variables.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf b/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf index 9cbd7b73..499ba87e 100644 --- a/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf +++ b/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf @@ -95,4 +95,4 @@ variable "cognito_base_url" { variable "cognito_user_pool_id" { description = "Cognito user pool id." type = string -} \ No newline at end of file +} diff --git a/terraform-unity/variables.tf b/terraform-unity/variables.tf index cb433c76..57f071cf 100644 --- a/terraform-unity/variables.tf +++ b/terraform-unity/variables.tf @@ -358,4 +358,4 @@ variable "cognito_base_url" { variable "cognito_user_pool_id" { description = "Cognito user pool id." type = string -} \ No newline at end of file +} From 188a63a05f59190ebd5ce8155575969744af659a Mon Sep 17 00:00:00 2001 From: Nikki <17799906+nikki-t@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:02:02 -0400 Subject: [PATCH 7/9] Fix formatting --- terraform-unity/main.tf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/terraform-unity/main.tf b/terraform-unity/main.tf index 0260c614..8ae47b82 100644 --- a/terraform-unity/main.tf +++ b/terraform-unity/main.tf @@ -58,10 +58,10 @@ module "unity-sps-airflow" { docker_images = var.airflow_docker_images helm_charts = var.helm_charts karpenter_node_pools = module.unity-sps-karpenter-node-config.karpenter_node_pools - cognito_client_id = var.cognito_client_id - cognito_client_secret = var.cognito_client_secret - cognito_base_url = var.cognito_base_url - cognito_user_pool_id = var.cognito_user_pool_id + cognito_client_id = var.cognito_client_id + cognito_client_secret = var.cognito_client_secret + cognito_base_url = var.cognito_base_url + cognito_user_pool_id = var.cognito_user_pool_id } module "unity-sps-ogc-processes-api" { From b7c4a1f95623e4601d1a902fc62993cc60486e23 Mon Sep 17 00:00:00 2001 From: Nikki <17799906+nikki-t@users.noreply.github.com> Date: Mon, 14 Oct 2024 16:17:54 -0400 Subject: [PATCH 8/9] Query SSM parameter store for Cognito app client data --- terraform-unity/main.tf | 4 ---- .../terraform-unity-sps-airflow/data.tf | 16 +++++++++++++++ .../terraform-unity-sps-airflow/main.tf | 8 ++++---- .../terraform-unity-sps-airflow/variables.tf | 20 ------------------- terraform-unity/variables.tf | 20 ------------------- 5 files changed, 20 insertions(+), 48 deletions(-) diff --git a/terraform-unity/main.tf b/terraform-unity/main.tf index 8ae47b82..6b816d47 100644 --- a/terraform-unity/main.tf +++ b/terraform-unity/main.tf @@ -58,10 +58,6 @@ module "unity-sps-airflow" { docker_images = var.airflow_docker_images helm_charts = var.helm_charts karpenter_node_pools = module.unity-sps-karpenter-node-config.karpenter_node_pools - cognito_client_id = var.cognito_client_id - cognito_client_secret = var.cognito_client_secret - cognito_base_url = var.cognito_base_url - cognito_user_pool_id = var.cognito_user_pool_id } module "unity-sps-ogc-processes-api" { diff --git a/terraform-unity/modules/terraform-unity-sps-airflow/data.tf b/terraform-unity/modules/terraform-unity-sps-airflow/data.tf index 2e136b5a..7b2c1975 100644 --- a/terraform-unity/modules/terraform-unity-sps-airflow/data.tf +++ b/terraform-unity/modules/terraform-unity-sps-airflow/data.tf @@ -47,3 +47,19 @@ data "aws_efs_file_system" "efs" { data "aws_ssm_parameter" "ssl_cert_arn" { name = "/unity/account/network/ssl" } + +data "aws_ssm_parameter" "cognito_base_url" { + name = "/unity/shared-services/cognito/domain" +} + +data "aws_ssm_parameter" "cognito_client_id" { + name = "/unity/dev/sps/cognito_client_id" +} + +data "aws_ssm_parameter" "cognito_client_secret" { + name = "/unity/dev/sps/cognito_client_secret" +} + +data "aws_ssm_parameter" "cognito_user_pool_id" { + name = "/unity/cs/security/shared-services-cognito-user-pool/user-pool-id" +} diff --git a/terraform-unity/modules/terraform-unity-sps-airflow/main.tf b/terraform-unity/modules/terraform-unity-sps-airflow/main.tf index 07cbeaa4..099f735e 100644 --- a/terraform-unity/modules/terraform-unity-sps-airflow/main.tf +++ b/terraform-unity/modules/terraform-unity-sps-airflow/main.tf @@ -386,10 +386,10 @@ resource "helm_release" "airflow" { karpenter_node_pools = join(",", var.karpenter_node_pools) cwl_dag_ecr_uri = "${data.aws_caller_identity.current.account_id}.dkr.ecr.us-west-2.amazonaws.com" webserver_config = indent(4, file("${path.module}/../../../airflow/config/webserver_config.py")) - cognito_client_id = var.cognito_client_id - cognito_client_secret = var.cognito_client_secret - cognito_base_url = var.cognito_base_url - cognito_user_pool_id = var.cognito_user_pool_id + cognito_client_id = data.aws_ssm_parameter.cognito_client_id.value + cognito_client_secret = data.aws_ssm_parameter.cognito_client_secret.value + cognito_base_url = data.aws_ssm_parameter.cognito_base_url.value + cognito_user_pool_id = data.aws_ssm_parameter.cognito_user_pool_id.value }) ] set_sensitive { diff --git a/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf b/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf index 499ba87e..3f6ff754 100644 --- a/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf +++ b/terraform-unity/modules/terraform-unity-sps-airflow/variables.tf @@ -76,23 +76,3 @@ variable "karpenter_node_pools" { description = "Names of the Karpenter node pools" type = list(string) } - -variable "cognito_client_id" { - description = "Cognito user pool client id for application." - type = string -} - -variable "cognito_client_secret" { - description = "Cognito user pool client secret for application." - type = string -} - -variable "cognito_base_url" { - description = "Cognito user pool URL." - type = string -} - -variable "cognito_user_pool_id" { - description = "Cognito user pool id." - type = string -} diff --git a/terraform-unity/variables.tf b/terraform-unity/variables.tf index 57f071cf..eed6e71a 100644 --- a/terraform-unity/variables.tf +++ b/terraform-unity/variables.tf @@ -339,23 +339,3 @@ variable "dag_catalog_repo" { dags_directory_path = "airflow/dags" } } - -variable "cognito_client_id" { - description = "Cognito user pool client id for application." - type = string -} - -variable "cognito_client_secret" { - description = "Cognito user pool client secret for application." - type = string -} - -variable "cognito_base_url" { - description = "Cognito user pool URL." - type = string -} - -variable "cognito_user_pool_id" { - description = "Cognito user pool id." - type = string -} From 3ce5414d4c2462b8be62406b07fbdc31dd8e17e4 Mon Sep 17 00:00:00 2001 From: Nikki <17799906+nikki-t@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:36:55 -0400 Subject: [PATCH 9/9] Query shared services SSM parameters for Cognito data --- .../modules/terraform-unity-sps-airflow/data.tf | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/terraform-unity/modules/terraform-unity-sps-airflow/data.tf b/terraform-unity/modules/terraform-unity-sps-airflow/data.tf index 7b2c1975..d1b5a256 100644 --- a/terraform-unity/modules/terraform-unity-sps-airflow/data.tf +++ b/terraform-unity/modules/terraform-unity-sps-airflow/data.tf @@ -48,18 +48,22 @@ data "aws_ssm_parameter" "ssl_cert_arn" { name = "/unity/account/network/ssl" } +data "aws_ssm_parameter" "ss_acct_num" { + name = "/unity/shared-services/aws/account" +} + data "aws_ssm_parameter" "cognito_base_url" { - name = "/unity/shared-services/cognito/domain" + name = "arn:aws:ssm:us-west-2:${data.aws_ssm_parameter.ss_acct_num.value}:parameter/unity/shared-services/cognito/base-url" } data "aws_ssm_parameter" "cognito_client_id" { - name = "/unity/dev/sps/cognito_client_id" + name = "arn:aws:ssm:us-west-2:${data.aws_ssm_parameter.ss_acct_num.value}:parameter/unity/shared-services/cognito/airflow-ui-client-id" } data "aws_ssm_parameter" "cognito_client_secret" { - name = "/unity/dev/sps/cognito_client_secret" + name = "arn:aws:ssm:us-west-2:${data.aws_ssm_parameter.ss_acct_num.value}:parameter/unity/shared-services/cognito/airflow-ui-client-secret" } data "aws_ssm_parameter" "cognito_user_pool_id" { - name = "/unity/cs/security/shared-services-cognito-user-pool/user-pool-id" -} + name = "arn:aws:ssm:us-west-2:${data.aws_ssm_parameter.ss_acct_num.value}:parameter/unity/shared-services/cognito/user-pool-id" +} \ No newline at end of file