From 0c14c28f31c5cbd626a2d0667337325a9e3f964d Mon Sep 17 00:00:00 2001 From: Erik Schultink Date: Wed, 27 May 2026 08:45:32 -0700 Subject: [PATCH 1/2] Update example to v0.6.1 --- google-workspace.tf | 2 +- main.tf | 9 ++++++--- msft-365.tf | 8 ++++---- variables.tf | 40 +++++++++++++++++++++++++++++++++++----- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/google-workspace.tf b/google-workspace.tf index 646cdff..9def5b2 100644 --- a/google-workspace.tf +++ b/google-workspace.tf @@ -7,7 +7,7 @@ provider "google" { module "worklytics_connectors_google_workspace" { - source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-google-workspace?ref=v0.6.0" + source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-google-workspace?ref=v0.6.1" google_workspace_connector_settings = var.google_workspace_connector_settings diff --git a/main.tf b/main.tf index a38a374..b51aa0b 100644 --- a/main.tf +++ b/main.tf @@ -20,7 +20,7 @@ terraform { # general cases module "worklytics_connectors" { - source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors?ref=v0.6.0" + source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors?ref=v0.6.1" enabled_connectors = var.enabled_connectors connector_settings = var.connector_settings @@ -111,7 +111,7 @@ locals { } module "psoxy" { - source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-host?ref=v0.6.0" + source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-host?ref=v0.6.1" environment_name = var.environment_name aws_account_id = var.aws_account_id @@ -140,6 +140,8 @@ module "psoxy" { secrets_store_implementation = var.secrets_store_implementation bulk_sanitized_expiration_days = var.bulk_sanitized_expiration_days bulk_input_expiration_days = var.bulk_input_expiration_days + allowed_data_access_ip_blocks = var.allowed_data_access_ip_blocks + allowed_webhook_ip_blocks = var.allowed_webhook_ip_blocks api_connectors = local.api_connectors bulk_connectors = local.bulk_connectors webhook_collectors = { for k, v in var.webhook_collectors : k => merge( @@ -154,6 +156,7 @@ module "psoxy" { custom_side_outputs = var.custom_side_outputs todo_step = local.max_auth_todo_step todos_as_local_files = var.todos_as_local_files + enable_remote_resources = true # vpc_config = { @@ -185,7 +188,7 @@ locals { module "connection_in_worklytics" { for_each = local.all_instances - source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-proxy-connection-aws?ref=v0.6.0" + source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-proxy-connection-aws?ref=v0.6.1" proxy_instance_id = each.key worklytics_host = var.worklytics_host diff --git a/msft-365.tf b/msft-365.tf index 4b17a36..570f230 100644 --- a/msft-365.tf +++ b/msft-365.tf @@ -1,7 +1,7 @@ # BEGIN MSFT module "worklytics_connectors_msft_365" { - source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-msft-365?ref=v0.6.0" + source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-msft-365?ref=v0.6.1" msft_365_connector_settings = var.msft_365_connector_settings @@ -50,7 +50,7 @@ data "aws_region" "current" { module "cognito_identity_pool" { count = local.msft_365_enabled ? 1 : 0 # only provision identity pool if MSFT-365 connectors are enabled - source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-cognito-pool?ref=v0.6.0" + source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-cognito-pool?ref=v0.6.1" developer_provider_name = local.developer_provider_name name = "${local.env_qualifier}-azure-ad-federation" @@ -72,7 +72,7 @@ locals { module "cognito_identity" { count = local.msft_365_enabled ? 1 : 0 # only provision identity pool if MSFT-365 connectors are enabled - source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-cognito-identity-cli?ref=v0.6.0" + source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-cognito-identity-cli?ref=v0.6.1" aws_region = data.aws_region.current.id @@ -109,7 +109,7 @@ locals { module "msft_connection_auth_federation" { for_each = local.provision_entraid_apps ? local.enabled_to_entraid_object : local.shared_to_entraid_object - source = "git::https://github.com/worklytics/psoxy//infra/modules/azuread-federated-credentials?ref=v0.6.0" + source = "git::https://github.com/worklytics/psoxy//infra/modules/azuread-federated-credentials?ref=v0.6.1" application_id = each.value.connector_id display_name = "${local.env_qualifier}AccessFromAWS" diff --git a/variables.tf b/variables.tf index 76c7897..7f33d14 100644 --- a/variables.tf +++ b/variables.tf @@ -469,6 +469,40 @@ variable "lookup_table_builders" { } } +variable "allowed_data_access_ip_blocks" { + description = <<-EOT + IPs or CIDR blocks allowed to make data access requests. On AWS, enforces at IAM (assume-role aws:SourceIp) and in the proxy. Use null (default) for no restriction. If set, the list must contain at least one value. See docs/configuration/ip-allowlisting.md. + EOT + type = list(string) + nullable = true + default = null + + validation { + condition = var.allowed_data_access_ip_blocks == null || try(length(var.allowed_data_access_ip_blocks) > 0, false) + error_message = "allowed_data_access_ip_blocks must be null (allow all) or a non-empty list; an empty list is invalid." + } +} + +variable "allowed_webhook_ip_blocks" { + description = <<-EOT + IPs or CIDR blocks allowed to send webhooks. On AWS, enforces at IAM (webhook-test-caller aws:SourceIp) and in the proxy. Use null (default) for no restriction. If set, the list must contain at least one value. See docs/configuration/ip-allowlisting.md. + EOT + type = list(string) + nullable = true + default = null + + validation { + condition = var.allowed_webhook_ip_blocks == null || try(length(var.allowed_webhook_ip_blocks) > 0, false) + error_message = "allowed_webhook_ip_blocks must be null (allow all) or a non-empty list; an empty list is invalid." + } +} + +variable "connector_settings" { + type = map(string) + default = {} + description = "Connector-specific settings." +} + variable "todos_as_outputs" { type = bool description = "whether to render TODOs as outputs (former useful if you're using Terraform Cloud/Enterprise, or somewhere else where the filesystem is not readily accessible to you)" @@ -481,8 +515,4 @@ variable "todos_as_local_files" { default = true } -variable "connector_settings" { - type = map(string) - default = {} - description = "Connector-specific settings." -} + From 9f535428fcee867df5aedcfa7192826c6685e600 Mon Sep 17 00:00:00 2001 From: Erik Schultink Date: Wed, 27 May 2026 08:46:51 -0700 Subject: [PATCH 2/2] add prefligh, az-auth scripts --- az-auth | 54 ++++++++++++++++++++++++++++++++++++++ preflight | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100755 az-auth create mode 100755 preflight diff --git a/az-auth b/az-auth new file mode 100755 index 0000000..776abab --- /dev/null +++ b/az-auth @@ -0,0 +1,54 @@ +#!/bin/bash + +# Copyright 2025 Worklytics, Co. + +# Sandbox Azure CLI auth to the current directory to prevent conflicts with other Azure tenants +export AZURE_CONFIG_DIR="${PWD}/.azure" + +COLORSCHEME_SH="$(dirname "$0")/set-term-colorscheme.sh" +if [ -f "$COLORSCHEME_SH" ]; then + source "$COLORSCHEME_SH" +else + ERR='\033[0;31m'; SUCCESS='\033[0;32m'; WARN='\033[1;33m'; INFO='\033[0;34m'; CODE='\033[0;36m'; NC='\033[0m' +fi + +printf "Sandboxing Azure CLI authentication state to ${INFO}${AZURE_CONFIG_DIR}${NC}\n" + +if ! az -v &> /dev/null ; then + printf "${ERR}Azure CLI not available.${NC}\n" + exit 1 +fi + +TENANT_ID=$1 +if [ -f "terraform.tfvars" ] && [ -z "$TENANT_ID" ]; then + if ! terraform -v &> /dev/null ; then + printf "${ERR}Terraform not available.${NC}\n" + exit 1 + fi + + TENANT_ID=$(grep -E "^msft_tenant_id" terraform.tfvars | awk -F'=' '{print $2}' | tr -d '"' | xargs) + TENANT_ID_PATTERN='^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$' + + if [[ ! "$TENANT_ID" =~ $TENANT_ID_PATTERN ]]; then + printf "${ERR}Error: Failed to parse Microsoft Tenant ID from terraform.tfvars; you can pass as an argument to this tool. Example:${NC}\n" + printf "Usage: ${INFO}./az-auth.sh ${NC}\n" + printf "Parsed value was: ${INFO}$TENANT_ID${NC}\n" + exit 1 + fi +fi + +CURRENT_TENANT_ID=$(az account show --query tenantId -o tsv 2>/dev/null) + +if [ "$CURRENT_TENANT_ID" != "$TENANT_ID" ]; then + if [ -z "$CURRENT_TENANT_ID" ]; then + printf "No current active Azure session.\n" + else + printf "Current tenant is ${INFO}${CURRENT_TENANT_ID}${NC}.\r\n" + fi + printf "Azure (Microsoft 365) tenant will be forced to ${SUCCESS}${TENANT_ID}${NC}, parsed from your ${INFO}terraform.tfvars${NC}. If you pick user from different tenant, auth will fail.\r\n" + TENANT_ID_CLAUSE="--tenant ${TENANT_ID}" + az login --allow-no-subscriptions $TENANT_ID_CLAUSE +else + printf "Current Azure account is already authenticated against the specified tenant ID ${INFO}${TENANT_ID}${NC}. ${SUCCESS}OK${NC}.\n" +fi + diff --git a/preflight b/preflight new file mode 100755 index 0000000..9b2c7ab --- /dev/null +++ b/preflight @@ -0,0 +1,78 @@ +#!/bin/bash + +# script to check if Terraform cloud providers have basic authentication +# configured correctly based on variables.tf and environment variables +set -e + +if [ -f "$(dirname "$0")/set-term-colorscheme.sh" ]; then + source "$(dirname "$0")/set-term-colorscheme.sh" +elif [ -f "$(dirname "$0")/../../tools/set-term-colorscheme.sh" ]; then + source "$(dirname "$0")/../../tools/set-term-colorscheme.sh" +else + # Fallbacks + ERR='\033[0;31m'; SUCCESS='\033[0;32m'; WARN='\033[1;33m'; INFO='\033[0;34m'; CODE='\033[0;36m'; NC='\033[0m' +fi + +printf "${INFO}Running preflight checks for Terraform providers ...${NC}\n\n" + +# ======== AWS Check ======== +if grep -q 'provider "aws"' *.tf 2>/dev/null || grep -q 'aws_assume_role_arn' variables.tf 2>/dev/null; then + printf "Checking AWS Provider Auth...\n" + if ! aws sts get-caller-identity &> /dev/null; then + printf " ${ERR}AWS CLI is not authenticated.${NC} Run 'aws configure' or 'aws sso login'.\n" + else + printf " ${SUCCESS}AWS CLI is authenticated.${NC}\n" + # Attempt to extract assumed role from tfvars if it exists + if [ -f "terraform.tfvars" ]; then + ASSUME_ROLE=$(grep "aws_assume_role_arn" terraform.tfvars | cut -d "=" -f 2 | tr -d ' "') || true + if [[ -n "$ASSUME_ROLE" && "$ASSUME_ROLE" != "null" ]]; then + printf " Attempting to assume AWS Role: ${CODE}${ASSUME_ROLE}${NC} ...\n" + if aws sts assume-role --role-arn "$ASSUME_ROLE" --role-session-name "preflight-test" &> /dev/null; then + printf " ${SUCCESS}Successfully assumed AWS Role from TFVars.${NC}\n" + else + printf " ${ERR}Failed to assume AWS role: $ASSUME_ROLE.${NC} Check trust policies and permissions.\n" + fi + fi + fi + fi + printf "\n" +fi + +# ======== GCP Check ======== +if grep -q 'provider "google"' *.tf 2>/dev/null || grep -q 'provider "google-workspace"' *.tf 2>/dev/null || grep -q 'provider "google-beta"' *.tf 2>/dev/null; then + printf "Checking GCP Provider Auth...\n" + if ! gcloud auth list --filter="status:ACTIVE" --format="value(account)" 2>/dev/null | grep -q '@'; then + printf " ${ERR}Google Cloud CLI is not authenticated.${NC} Run 'gcloud auth login' and 'gcloud auth application-default login'.\n" + else + printf " ${SUCCESS}Google Cloud CLI is authenticated.${NC}\n" + # Attempt to extract impersonated service account if configured + if [ -f "terraform.tfvars" ]; then + IMPERSONATE_SA=$(grep "gcp_terraform_sa_account_email" terraform.tfvars | cut -d "=" -f 2 | tr -d ' "') || true + if [[ -n "$IMPERSONATE_SA" && "$IMPERSONATE_SA" != "null" ]]; then + printf " Attempting to impersonate GCP Service Account: ${CODE}${IMPERSONATE_SA}${NC} ...\n" + # Testing impersonation by getting an access token + if gcloud auth print-access-token --impersonate-service-account="$IMPERSONATE_SA" &> /dev/null; then + printf " ${SUCCESS}Successfully impersonated GCP Service Account via gcloud.${NC}\n" + else + printf " ${ERR}Failed to impersonate Service Account: ${IMPERSONATE_SA}.${NC}\n" + fi + fi + fi + fi + printf "\n" +fi + +# ======== Azure/AzureAD Check ======== +if grep -q 'provider "azuread"' *.tf 2>/dev/null || grep -q 'provider "azurerm"' *.tf 2>/dev/null; then + printf "Checking Azure Provider Auth...\n" + if ! az account show &> /dev/null; then + printf " ${ERR}Azure CLI is not authenticated.${NC} Run 'az login' or 'az login --allow-no-subscription'.\n" + else + printf " ${SUCCESS}Azure CLI is authenticated.${NC}\n" + TENANT_ID=$(az account show --query tenantId -o tsv) + printf " Current Azure Tenant: ${CODE}${TENANT_ID}${NC}\n" + fi + printf "\n" +fi + +printf "${SUCCESS}Preflight checks complete.${NC}\n"