From be2371ca4d763197c066e25720c1436849e24764 Mon Sep 17 00:00:00 2001 From: Kevin Date: Mon, 13 Mar 2023 10:37:10 -0700 Subject: [PATCH 1/7] feat: use assume role to access org read role --- lambda.tf | 30 ++++++++++++++++++++++++++---- lambda/samlpost/index.js | 11 +++-------- main.tf | 7 +++++++ 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/lambda.tf b/lambda.tf index bba224e..0e75cf3 100644 --- a/lambda.tf +++ b/lambda.tf @@ -21,10 +21,10 @@ resource "aws_lambda_function" "samlpost" { environment { variables = { - samlReadRole = "arn:aws:iam::${local.master_account_id}:saml-provider/${var.keycloak_saml_name},arn:aws:iam::${local.master_account_id}:role/${local.saml_read_role_name}", - kc_base_url = var.kc_base_url, - kc_realm = var.kc_realm, - kc_terraform_auth_client_id = var.kc_terraform_auth_client_id, + samlReadRole = "arn:aws:iam::${local.master_account_id}:saml-provider/${var.keycloak_saml_name},arn:aws:iam::${local.master_account_id}:role/${local.saml_read_role_name}", + kc_base_url = var.kc_base_url, + kc_realm = var.kc_realm, + kc_terraform_auth_client_id = var.kc_terraform_auth_client_id, kc_terraform_auth_client_secret = var.kc_terraform_auth_client_secret } } @@ -66,6 +66,28 @@ resource "aws_iam_role_policy_attachment" "test-attach" { policy_arn = data.aws_iam_policy.AWSLambdaBasicExecutionRole.arn } +resource "aws_iam_policy" "assume_role_org_read" { + provider = aws.iam-security-account + name = "serverless_saml_lambda-org-read-${var.resource_name_suffix}" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Action = [ + "sts:AssumeRole" + ] + Resource = "${aws_iam_role.saml_read_role.arn}" + }] + }) +} + +resource "aws_iam_role_policy_attachment" "thisSTS" { + provider = aws.iam-security-account + role = aws_iam_role.lambda_exec.name + policy_arn = aws_iam_policy.assume_role_org_read.arn +} + resource "aws_lambda_permission" "apigw" { provider = aws.iam-security-account diff --git a/lambda/samlpost/index.js b/lambda/samlpost/index.js index 12c27ac..7788c6d 100644 --- a/lambda/samlpost/index.js +++ b/lambda/samlpost/index.js @@ -50,24 +50,19 @@ exports.handler = function (event, context, callback) { if (checkSAMLForAzureIDP(decodedsamlResponse)) { transferKeyCloakGroups(decodedsamlResponse) } - let accounts = parseSAMLResponse(decodedsamlResponse); + let accounts = parseSAMLResponse(decodedsamlResponse); let saml_read_role = process.env.samlReadRole.split(","); - - let principalArn = saml_read_role[0]; let roleArn = saml_read_role[1]; - let samlResponse = body.samlResponse; - let sts = new AWS.STS(); let params = { DurationSeconds: 900, - PrincipalArn: principalArn, RoleArn: roleArn, - SAMLAssertion: samlResponse + RoleSessionName: "AWSLoginAppOrgRead" }; - sts.assumeRoleWithSAML(params, function (err, data) { + sts.assumeRole(params, function (err, data) { if (err) { console.log(err, err.stack); var response = { diff --git a/main.tf b/main.tf index 433ea2c..6457e15 100644 --- a/main.tf +++ b/main.tf @@ -68,6 +68,13 @@ resource "aws_iam_role" "saml_read_role" { "SAML:aud": "${local.saml_destination_url}" } } + }, + { + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::${local.iam_security_account.id}:role/serverless_saml_lambda-dev" + }, + "Action": "sts:AssumeRole" } ] } From 59ac7c0bca956795ced4df9f4954c3aa86177c23 Mon Sep 17 00:00:00 2001 From: Kevin Date: Mon, 13 Mar 2023 10:40:35 -0700 Subject: [PATCH 2/7] feat: use domain_name for the login app --- cloudfront.tf | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++- main.tf | 31 +++++++++++++++++++++---- variables.tf | 5 ++++ 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/cloudfront.tf b/cloudfront.tf index e5f4fd5..92782d4 100644 --- a/cloudfront.tf +++ b/cloudfront.tf @@ -2,6 +2,58 @@ locals { cf_origin_id = "api_gateway_saml" } +data "aws_route53_zone" "this" { + provider = aws.perimeter-account + name = var.domain_name +} + +resource "aws_route53_record" "login_app" { + provider = aws.perimeter-account + zone_id = data.aws_route53_zone.this.zone_id + name = "login.${var.domain_name}" + type = "A" + + alias { + name = aws_cloudfront_distribution.geofencing.domain_name + zone_id = aws_cloudfront_distribution.geofencing.hosted_zone_id + evaluate_target_health = false + } +} + +resource "aws_acm_certificate" "this" { + provider = aws.iam-security-account-us-east-1 + domain_name = "login.${var.domain_name}" + validation_method = "DNS" + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_route53_record" "this_acm" { + provider = aws.perimeter-account + for_each = { + for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => { + name = dvo.resource_record_name + record = dvo.resource_record_value + type = dvo.resource_record_type + } + } + + allow_overwrite = true + name = each.value.name + records = [each.value.record] + ttl = 60 + type = each.value.type + zone_id = data.aws_route53_zone.this.zone_id +} + +resource "aws_acm_certificate_validation" "this" { + provider = aws.iam-security-account-us-east-1 + certificate_arn = aws_acm_certificate.this.arn + validation_record_fqdns = [for record in aws_route53_record.this_acm : record.fqdn] +} + resource "aws_cloudfront_distribution" "geofencing" { provider = aws.iam-security-account @@ -62,6 +114,8 @@ resource "aws_cloudfront_distribution" "geofencing" { max_ttl = 86400 } + aliases = ["login.${var.domain_name}"] + price_class = "PriceClass_100" restrictions { @@ -75,10 +129,17 @@ resource "aws_cloudfront_distribution" "geofencing" { tags = local.common_tags viewer_certificate { - cloudfront_default_certificate = true + cloudfront_default_certificate = false + acm_certificate_arn = aws_acm_certificate_validation.this.certificate_arn + minimum_protocol_version = "TLSv1.2_2021" + ssl_support_method = "sni-only" } } output "cloudfront_url" { value = "https://${aws_cloudfront_distribution.geofencing.domain_name}/${aws_api_gateway_deployment.samlpost.stage_name}" } + +output "login_domain_name" { + value = "https://login.${var.domain_name}/${aws_api_gateway_deployment.samlpost.stage_name}" +} \ No newline at end of file diff --git a/main.tf b/main.tf index 6457e15..6c8d26f 100644 --- a/main.tf +++ b/main.tf @@ -19,6 +19,26 @@ provider "aws" { } } +provider "aws" { + region = "us-east-1" + alias = "iam-security-account-us-east-1" + + assume_role { + role_arn = "arn:aws:iam::${local.iam_security_account.id}:role/AWSCloudFormationStackSetExecutionRole" + session_name = "slz-terraform-automation" + } +} + +provider "aws" { + region = "ca-central-1" + alias = "perimeter-account" + + assume_role { + role_arn = "arn:aws:iam::${local.perimeter_account.id}:role/AWSCloudFormationStackSetExecutionRole" + session_name = "slz-terraform-automation" + } +} + module "lz_info" { source = "github.com/BCDevOps/terraform-aws-sea-organization-info" providers = { @@ -32,9 +52,10 @@ data "aws_caller_identity" "master_account_caller" { locals { - core_accounts = { for account in module.lz_info.core_accounts : account.name => account } - iam_security_account = local.core_accounts["iam-security"] - saml_destination_url = "https://${aws_cloudfront_distribution.geofencing.domain_name}/${aws_api_gateway_deployment.samlpost.stage_name}" + core_accounts = { for account in module.lz_info.core_accounts : account.name => account } + iam_security_account = local.core_accounts["iam-security"] + perimeter_account = local.core_accounts["Perimeter"] + saml_destination_url = "https://login.${var.domain_name}/${aws_api_gateway_deployment.samlpost.stage_name}" //Put all common tags here @@ -95,7 +116,7 @@ resource "aws_iam_role_policy" "saml_read_role_policy" { "Effect": "Allow", "Action": [ "organizations:ListTagsForResource", - "organizations:DescribeAccount" + "organizations:DescribeAccount" ], "Resource": [ "*" @@ -104,4 +125,4 @@ resource "aws_iam_role_policy" "saml_read_role_policy" { ] } EOF -} +} \ No newline at end of file diff --git a/variables.tf b/variables.tf index f003c97..407cdd3 100644 --- a/variables.tf +++ b/variables.tf @@ -31,4 +31,9 @@ variable "kc_terraform_auth_client_secret" { description = "The authentication secret of the keycloak client used for terraform automation" type = string default = "" +} + +variable "domain_name" { + description = "Domain name of the login app" + type = string } \ No newline at end of file From a2b1632ca66da33bd2c8e36612a0fbb0e2a3ed31 Mon Sep 17 00:00:00 2001 From: Kevin Date: Mon, 13 Mar 2023 10:48:00 -0700 Subject: [PATCH 3/7] feat: add redirection from root to keycloack --- apigateway.tf | 2 +- cloudfront.tf | 1 + lambda/samlpost/index.js | 15 ++++++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apigateway.tf b/apigateway.tf index 296f944..368ce20 100644 --- a/apigateway.tf +++ b/apigateway.tf @@ -1,7 +1,7 @@ resource "aws_api_gateway_rest_api" "samlpost" { provider = aws.iam-security-account - name = "SAMLPostExample" + name = "LoginAppSAML" description = "Terraform Serverless Application Example" tags = local.common_tags diff --git a/cloudfront.tf b/cloudfront.tf index 92782d4..71bac47 100644 --- a/cloudfront.tf +++ b/cloudfront.tf @@ -115,6 +115,7 @@ resource "aws_cloudfront_distribution" "geofencing" { } aliases = ["login.${var.domain_name}"] + default_root_object = "${aws_api_gateway_deployment.samlpost.stage_name}/redirect" price_class = "PriceClass_100" diff --git a/lambda/samlpost/index.js b/lambda/samlpost/index.js index 7788c6d..75caedc 100644 --- a/lambda/samlpost/index.js +++ b/lambda/samlpost/index.js @@ -7,7 +7,20 @@ let https = require('https'); var qs = require('querystring'); exports.handler = function (event, context, callback) { - if (event.path == "/" && event.httpMethod == "POST") { + if (event.path == "/redirect" && event.httpMethod == "GET") { + const kc_base_url = process.env.kc_base_url; + const kc_realm = process.env.kc_realm; + const response = { + statusCode: 301, + headers: { + Location: 'https://' + kc_base_url + '/auth/realms/' + kc_realm + '/protocol/saml/clients/amazon-aws', + } + }; + + callback(null, response) + } + + else if (event.path == "/" && event.httpMethod == "POST") { const fileName = "index.html"; let resolved = null; From b9f5c034087f5e250524a853d94727aaaa3b05e0 Mon Sep 17 00:00:00 2001 From: Kevin Date: Mon, 13 Mar 2023 10:48:20 -0700 Subject: [PATCH 4/7] formating lambda code --- lambda/samlpost/index.js | 398 ++++++++++++++++++++------------------- 1 file changed, 200 insertions(+), 198 deletions(-) diff --git a/lambda/samlpost/index.js b/lambda/samlpost/index.js index 75caedc..d6d5526 100644 --- a/lambda/samlpost/index.js +++ b/lambda/samlpost/index.js @@ -21,235 +21,237 @@ exports.handler = function (event, context, callback) { } else if (event.path == "/" && event.httpMethod == "POST") { - const fileName = "index.html"; + const fileName = "index.html"; - let resolved = null; - if (process.env.LAMBDA_TASK_ROOT) { - resolved = path.resolve(process.env.LAMBDA_TASK_ROOT, fileName); - } else { - resolved = path.resolve(__dirname, fileName); - } - - const data = fs.readFileSync(resolved, 'utf8'); + let resolved = null; + if (process.env.LAMBDA_TASK_ROOT) { + resolved = path.resolve(process.env.LAMBDA_TASK_ROOT, fileName); + } else { + resolved = path.resolve(__dirname, fileName); + } - let samlResponse = event.body.replace('SAMLResponse=', ''); - const temp_rolearn = process.env.samlReadRole.split(",")[1]; - const serverless_saml_user_account_read_role = temp_rolearn.substr(temp_rolearn.lastIndexOf("/")+1); + const data = fs.readFileSync(resolved, 'utf8'); - let html = data.replace("##SAMLRESPONSE##", decodeURIComponent(samlResponse)).replace("##serverless_saml_user_account_read_role##", serverless_saml_user_account_read_role); + let samlResponse = event.body.replace('SAMLResponse=', ''); + const temp_rolearn = process.env.samlReadRole.split(",")[1]; + const serverless_saml_user_account_read_role = temp_rolearn.substr(temp_rolearn.lastIndexOf("/") + 1); - var response = { - statusCode: 200, - headers: { - 'Content-Type': 'text/html; charset=utf-8', - 'Access-Control-Allow-Origin': '*',// Required for CORS support to work - 'Access-Control-Allow-Headers': '*', - "Access-Control-Allow-Methods": "OPTIONS,POST,GET" - }, - body: html - } + let html = data.replace("##SAMLRESPONSE##", decodeURIComponent(samlResponse)).replace("##serverless_saml_user_account_read_role##", serverless_saml_user_account_read_role); - callback(null, response) + var response = { + statusCode: 200, + headers: { + 'Content-Type': 'text/html; charset=utf-8', + 'Access-Control-Allow-Origin': '*',// Required for CORS support to work + 'Access-Control-Allow-Headers': '*', + "Access-Control-Allow-Methods": "OPTIONS,POST,GET" + }, + body: html } - else if (event.path == "/accounttags" && event.httpMethod == "POST") { - if (event.body) { - let body = JSON.parse(event.body); + callback(null, response) + } + + else if (event.path == "/accounttags" && event.httpMethod == "POST") { + if (event.body) { + + let body = JSON.parse(event.body); - let buff = Buffer.from(body.samlResponse, "base64"); - let decodedsamlResponse = buff.toString("utf-8"); + let buff = Buffer.from(body.samlResponse, "base64"); + let decodedsamlResponse = buff.toString("utf-8"); - // check if azure ad idir user is logged in - if (checkSAMLForAzureIDP(decodedsamlResponse)) { - transferKeyCloakGroups(decodedsamlResponse) - } + // check if azure ad idir user is logged in + if (checkSAMLForAzureIDP(decodedsamlResponse)) { + transferKeyCloakGroups(decodedsamlResponse) + } - let accounts = parseSAMLResponse(decodedsamlResponse); - let saml_read_role = process.env.samlReadRole.split(","); - let roleArn = saml_read_role[1]; - let sts = new AWS.STS(); + let accounts = parseSAMLResponse(decodedsamlResponse); + let saml_read_role = process.env.samlReadRole.split(","); + let roleArn = saml_read_role[1]; + let sts = new AWS.STS(); - let params = { - DurationSeconds: 900, - RoleArn: roleArn, + let params = { + DurationSeconds: 900, + RoleArn: roleArn, RoleSessionName: "AWSLoginAppOrgRead" - }; + }; sts.assumeRole(params, function (err, data) { - if (err) { - console.log(err, err.stack); - var response = { - statusCode: 500, - body: JSON.stringify(err) - }; - - callback(null, response); - } else { - let organizations = new AWS.Organizations({ - accessKeyId: data.Credentials.AccessKeyId, - secretAccessKey: data.Credentials.SecretAccessKey, - sessionToken: data.Credentials.SessionToken, - region: "us-east-1"}); - - var getTagsForAccounts = function getTagsForAccounts(accountData, orgClient) { - return Promise.all(Object.keys(accountData).map(function(account) { - return new Promise((resolve, reject) => { - organizations.listTagsForResource({ResourceId: account}, function (err, data){ - if (err) { - reject(err); - } - let accountTags = {}; - accountTags.accountId = account; - accountTags.tags = data.Tags; - organizations.describeAccount({AccountId: account}, function (e, d) { - if (e) { - console.log(e); - reject(e); - } - - accountTags.accountName = d.Account.Name; - resolve(accountTags); - }); - }); - }); - })) - }; - - getTagsForAccounts(accounts, organizations) - .then((values) =>{ - let returnVal = {}; - for (const val of values) { - returnVal[val.accountId] = val; - } - - var response = { - statusCode: 200, - body: JSON.stringify(returnVal) - }; - - callback(null, response); - }); - } + if (err) { + console.log(err, err.stack); + var response = { + statusCode: 500, + body: JSON.stringify(err) + }; + + callback(null, response); + } else { + let organizations = new AWS.Organizations({ + accessKeyId: data.Credentials.AccessKeyId, + secretAccessKey: data.Credentials.SecretAccessKey, + sessionToken: data.Credentials.SessionToken, + region: "us-east-1" + }); - }); + var getTagsForAccounts = function getTagsForAccounts(accountData, orgClient) { + return Promise.all(Object.keys(accountData).map(function (account) { + return new Promise((resolve, reject) => { + organizations.listTagsForResource({ ResourceId: account }, function (err, data) { + if (err) { + reject(err); + } + let accountTags = {}; + accountTags.accountId = account; + accountTags.tags = data.Tags; + organizations.describeAccount({ AccountId: account }, function (e, d) { + if (e) { + console.log(e); + reject(e); + } + accountTags.accountName = d.Account.Name; + resolve(accountTags); + }); + }); + }); + })) + }; + + getTagsForAccounts(accounts, organizations) + .then((values) => { + let returnVal = {}; + for (const val of values) { + returnVal[val.accountId] = val; + } + + var response = { + statusCode: 200, + body: JSON.stringify(returnVal) + }; + + callback(null, response); + }); } - } - else if (event.path == "/consolelogin" && event.httpMethod == "POST") { - if (event.body) { + }); - let body = JSON.parse(event.body); + } + } + else if (event.path == "/consolelogin" && event.httpMethod == "POST") { - let principalArn = body.PrincipalArn; - let roleArn = body.RoleArn; - let samlResponse = body.SAMLAssertion; - let duration = body.DurationSeconds; + if (event.body) { - let sts = new AWS.STS(); + let body = JSON.parse(event.body); - let params = { - DurationSeconds: duration, - PrincipalArn: principalArn, - RoleArn: roleArn, - SAMLAssertion: samlResponse - }; + let principalArn = body.PrincipalArn; + let roleArn = body.RoleArn; + let samlResponse = body.SAMLAssertion; + let duration = body.DurationSeconds; - sts.assumeRoleWithSAML(params, function (err, data) { - if (err) { - console.log(err, err.stack); - } else { + let sts = new AWS.STS(); - let accessKeyId = data.Credentials.AccessKeyId; - let secretKey = data.Credentials.SecretAccessKey; - let sessionToken = data.Credentials.SessionToken; - let issuer = data.Issuer; + let params = { + DurationSeconds: duration, + PrincipalArn: principalArn, + RoleArn: roleArn, + SAMLAssertion: samlResponse + }; - let st = - { - "sessionId": accessKeyId, - "sessionKey": secretKey, - "sessionToken": sessionToken - } + sts.assumeRoleWithSAML(params, function (err, data) { + if (err) { + console.log(err, err.stack); + } else { - let sessionTokenString = encodeURIComponent(JSON.stringify(st)); + let accessKeyId = data.Credentials.AccessKeyId; + let secretKey = data.Credentials.SecretAccessKey; + let sessionToken = data.Credentials.SessionToken; + let issuer = data.Issuer; - let requestParams = "?Action=getSigninToken"; - requestParams += `&SessionDuration=${duration}`; - requestParams += `&Session=${sessionTokenString}`; + let st = + { + "sessionId": accessKeyId, + "sessionKey": secretKey, + "sessionToken": sessionToken + } - let requestUrl = "https://signin.aws.amazon.com/federation" + requestParams; + let sessionTokenString = encodeURIComponent(JSON.stringify(st)); - https.get(requestUrl, (resp) => { - let data = ''; + let requestParams = "?Action=getSigninToken"; + requestParams += `&SessionDuration=${duration}`; + requestParams += `&Session=${sessionTokenString}`; - // A chunk of data has been recieved. - resp.on('data', (chunk) => { - data += chunk; - }); + let requestUrl = "https://signin.aws.amazon.com/federation" + requestParams; - // The whole response has been received. Print out the result. - resp.on('end', () => { - const signInToken = JSON.parse(data).SigninToken; + https.get(requestUrl, (resp) => { + let data = ''; - requestParams = "?Action=login"; - requestParams += `&Issuer=${issuer}`; - requestParams += `&Destination=https://console.aws.amazon.com/console/home?region=ca-central-1`; - requestParams += `&SigninToken=${signInToken}` + // A chunk of data has been recieved. + resp.on('data', (chunk) => { + data += chunk; + }); - requestUrl = "https://signin.aws.amazon.com/federation" + requestParams; + // The whole response has been received. Print out the result. + resp.on('end', () => { + const signInToken = JSON.parse(data).SigninToken; - var response = { - statusCode: 200, - body: JSON.stringify({ Location: requestUrl }) - }; + requestParams = "?Action=login"; + requestParams += `&Issuer=${issuer}`; + requestParams += `&Destination=https://console.aws.amazon.com/console/home?region=ca-central-1`; + requestParams += `&SigninToken=${signInToken}` - callback(null, response); + requestUrl = "https://signin.aws.amazon.com/federation" + requestParams; - }); + var response = { + statusCode: 200, + body: JSON.stringify({ Location: requestUrl }) + }; - }).on("error", (err) => { - console.log("Error: " + err.message); - }); + callback(null, response); - } }); - } - } - else { - var response = { - statusCode: 200, - body: "Unknown Method" + }).on("error", (err) => { + console.log("Error: " + err.message); + }); + } - callback(null, response) + }); + } + + } + else { + var response = { + statusCode: 200, + body: "Unknown Method" } + callback(null, response) + } } function parseSAMLResponse(samlResponse) { - //let capturingRegex = new RegExp(">(?arn:aws:iam::\\d+:saml-provider/\\S+),(?arn:aws::iam::(?\\d+):role/(?\\w+))<"); - let capturingRegex = new RegExp(">(arn:aws:iam::\\d+:saml-provider/[a-zA-Z0-9-_@=+.]+),(arn:aws:iam::(\\d+):role/([a-zA-Z0-9-_@=+.]+))<", "gi"); - ///>(arn:aws:iam::\d+:saml-provider\/\S+),(arn:aws:iam::(\d+):role\/(\w+))(?arn:aws:iam::\\d+:saml-provider/\\S+),(?arn:aws::iam::(?\\d+):role/(?\\w+))<"); + let capturingRegex = new RegExp(">(arn:aws:iam::\\d+:saml-provider/[a-zA-Z0-9-_@=+.]+),(arn:aws:iam::(\\d+):role/([a-zA-Z0-9-_@=+.]+))<", "gi"); + ///>(arn:aws:iam::\d+:saml-provider\/\S+),(arn:aws:iam::(\d+):role\/(\w+))\\S+@azureidir<", "gm"); let matches = saml_response.match(capturing_regex); let email = matches[0].replace('>', '').replace('@azureidir<', '') @@ -277,8 +279,8 @@ function parseSAMLForEmail(saml_response){ return email; } -function makeHttpRequest(options, post_data){ - return new Promise(function (resolve, reject){ +function makeHttpRequest(options, post_data) { + return new Promise(function (resolve, reject) { let req = https.request(options, function (res) { if (res.statusCode < 200 || res.statusCode >= 300) { return reject(new Error('statusCode=' + res.statusCode)); @@ -292,7 +294,7 @@ function makeHttpRequest(options, post_data){ resolve(body); }); }); - req.on('error', function(error){ + req.on('error', function (error) { reject(error); }); req.write(post_data); @@ -300,7 +302,7 @@ function makeHttpRequest(options, post_data){ }); } -async function getKeyCloakToken(){ +async function getKeyCloakToken() { let options = { 'method': 'POST', 'hostname': kc_base_url, @@ -318,7 +320,7 @@ async function getKeyCloakToken(){ return makeHttpRequest(options, post_data); } -async function getUsersWithEmail(headers, target_user_email){ +async function getUsersWithEmail(headers, target_user_email) { let options = { 'method': 'GET', 'hostname': kc_base_url, @@ -327,10 +329,10 @@ async function getUsersWithEmail(headers, target_user_email){ 'maxRedirects': 20 }; let post_data = qs.stringify({}); - return makeHttpRequest(options, post_data); + return makeHttpRequest(options, post_data); } -async function getSiteminderUserGroups(headers, siteminder_user_id){ +async function getSiteminderUserGroups(headers, siteminder_user_id) { let options = { 'method': 'GET', 'hostname': kc_base_url, @@ -339,10 +341,10 @@ async function getSiteminderUserGroups(headers, siteminder_user_id){ 'maxRedirects': 20 }; let post_data = qs.stringify({}); - return makeHttpRequest(options, post_data); + return makeHttpRequest(options, post_data); } -async function putAzureADUserGroup(headers, azure_ad_user_id, group_id){ +async function putAzureADUserGroup(headers, azure_ad_user_id, group_id) { let options = { 'method': 'PUT', 'hostname': kc_base_url, @@ -351,7 +353,7 @@ async function putAzureADUserGroup(headers, azure_ad_user_id, group_id){ 'maxRedirects': 20 }; let post_data = qs.stringify({}); - return makeHttpRequest(options, post_data); + return makeHttpRequest(options, post_data); } async function disableSiteminderUser(headers, siteminder_user_id) { @@ -368,10 +370,10 @@ async function disableSiteminderUser(headers, siteminder_user_id) { var post_data = JSON.stringify({ "enabled": false }); - return makeHttpRequest(options, post_data); + return makeHttpRequest(options, post_data); } -async function transferKeyCloakGroups(saml_response){ +async function transferKeyCloakGroups(saml_response) { console.log("In transferKeyCloakGroups(), transferring groups from Sitminder IDP user to Azure AD IDP user"); let token_response = await getKeyCloakToken(); From d15163c312bbb3284b671ce350d4a3fb5325736d Mon Sep 17 00:00:00 2001 From: Kevin Date: Mon, 13 Mar 2023 11:04:13 -0700 Subject: [PATCH 5/7] changing lambda name using variable --- lambda.tf | 4 ++-- main.tf | 2 +- variables.tf | 10 ++++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lambda.tf b/lambda.tf index 0e75cf3..91c1182 100644 --- a/lambda.tf +++ b/lambda.tf @@ -7,7 +7,7 @@ data "archive_file" "lambda_zip" { resource "aws_lambda_function" "samlpost" { provider = aws.iam-security-account - function_name = "SAMLPostExample-${var.resource_name_suffix}" + function_name = "${var.lambda_name}-${var.resource_name_suffix}" filename = data.archive_file.lambda_zip.output_path source_code_hash = data.archive_file.lambda_zip.output_base64sha256 @@ -35,7 +35,7 @@ resource "aws_lambda_function" "samlpost" { resource "aws_iam_role" "lambda_exec" { provider = aws.iam-security-account - name = "serverless_saml_lambda-${var.resource_name_suffix}" + name = "${var.lambda_name}-${var.resource_name_suffix}" assume_role_policy = < Date: Mon, 13 Mar 2023 11:04:28 -0700 Subject: [PATCH 6/7] fix: remove useless right --- main.tf | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/main.tf b/main.tf index 14f1d19..82a93bd 100644 --- a/main.tf +++ b/main.tf @@ -78,18 +78,6 @@ resource "aws_iam_role" "saml_read_role" { { "Version": "2012-10-17", "Statement": [ - { - "Effect": "Allow", - "Principal": { - "Federated": "arn:aws:iam::${local.master_account_id}:saml-provider/${var.keycloak_saml_name}" - }, - "Action": "sts:AssumeRoleWithSAML", - "Condition": { - "StringEquals": { - "SAML:aud": "${local.saml_destination_url}" - } - } - }, { "Effect": "Allow", "Principal": { From 50e268a3e5e7f68bdb7b6948ceab14a04d091ec9 Mon Sep 17 00:00:00 2001 From: Kevin Date: Mon, 13 Mar 2023 15:54:00 -0700 Subject: [PATCH 7/7] Move from test to api --- apigateway.tf | 2 +- lambda/samlpost/index.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apigateway.tf b/apigateway.tf index 368ce20..f9d6525 100644 --- a/apigateway.tf +++ b/apigateway.tf @@ -67,7 +67,7 @@ resource "aws_api_gateway_deployment" "samlpost" { rest_api_id = aws_api_gateway_rest_api.samlpost.id // @todo change value below to something like "saml" - stage_name = "test" + stage_name = "api" } diff --git a/lambda/samlpost/index.html b/lambda/samlpost/index.html index 1dd2787..6935425 100644 --- a/lambda/samlpost/index.html +++ b/lambda/samlpost/index.html @@ -301,7 +301,7 @@ $.ajax({ type: "POST", - url: "/test/accounttags", + url: "/api/accounttags", data: JSON.stringify({ samlResponse: samlResponse }), success: function (data, textStatus, jqXHR) { $("#loadingtags").remove(); @@ -397,7 +397,7 @@ $.ajax({ type: "POST", - url: "/test/consolelogin", + url: "/api/consolelogin", data: JSON.stringify(params), success: function (data, textStatus, jqXHR) { window.open(data.Location);