diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..57dcf49 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,83 @@ +# AI Agent Guide: Psoxy AWS Example Repository + +## What is This Repository? + +This is a **Terraform template repository** for deploying the [Worklytics Pseudonymizing Proxy (Psoxy)](https://github.com/Worklytics/psoxy) on **Amazon Web Services (AWS)**. + +Psoxy is a serverless, pseudonymizing Data Loss Prevention (DLP) layer that sits between Worklytics and your organization's data sources (SaaS APIs, cloud storage, etc.). It replaces PII with hash tokens, enabling analysis on anonymized data while enforcing access controls and compliance requirements. + +## Purpose + +This example repository provides: +- **Pre-configured Terraform modules** that reference the main Psoxy repository +- **Example configurations** for common data sources (Google Workspace, Microsoft 365, Slack, GitHub, etc.) +- **Helper scripts** for initialization, prerequisite checking, and testing +- **Infrastructure-as-code** templates ready for customization + +## Key Relationships + +- **Main Repository**: [https://github.com/Worklytics/psoxy](https://github.com/Worklytics/psoxy) + - Contains the core Psoxy Java implementation + - Provides Terraform modules used by this example + - Houses documentation and development resources + +- **Documentation**: [https://docs.worklytics.co/psoxy](https://docs.worklytics.co/psoxy) + - Comprehensive deployment guides + - Configuration reference + - Troubleshooting and best practices + - Data source-specific documentation + +- **This Example**: A template that customers clone and customize for their AWS deployment + +## How This Repository Works + +1. **Template Structure**: Customers use this as a GitHub template or clone it to create their own deployment repository +2. **Terraform Modules**: References modules from the main Psoxy repo via Git URLs (e.g., `git::https://github.com/worklytics/psoxy//infra/modules/...`) +3. **Version Pinning**: Each release of this example references a specific version tag of the main Psoxy repository +4. **Customization**: Customers modify `terraform.tfvars` and Terraform files to match their environment and data sources + +## Common Tasks for AI Agents + +### Understanding the Deployment + +- **Read the main README.md** in this repository for human-facing setup instructions +- **Review terraform.tfvars** to understand configuration variables +- **Examine main.tf** to see which modules are being used +- **Check available-connectors** script to see supported data sources + +### Helping Users Deploy + +1. **Prerequisites**: Guide users to run `./check-prereqs` and install missing tools +2. **Authentication**: Help configure AWS CLI, GCloud CLI (for Google Workspace), or Azure CLI (for Microsoft 365) +3. **Initialization**: Run `./init` to generate `terraform.tfvars` from prompts +4. **Customization**: Help users modify Terraform files to enable/disable data sources +5. **Deployment**: Guide through `terraform plan` and `terraform apply` + +### Troubleshooting + +- **Reference the main docs**: [https://docs.worklytics.co/psoxy](https://docs.worklytics.co/psoxy) +- **Check AWS-specific docs**: [https://docs.worklytics.co/psoxy/aws/getting-started](https://docs.worklytics.co/psoxy/aws/getting-started) +- **Review Terraform state** and error messages +- **Validate module versions** match the referenced Psoxy release + +### Code Navigation + +- **Terraform files** (`.tf`) define the infrastructure +- **Helper scripts** (`init`, `check-prereqs`, `available-connectors`) assist with setup +- **Module references** point to the main Psoxy repository at specific version tags +- **Example configurations** show how to enable various data source connectors + +## Important Notes + +- This is a **template repository** - users should create their own copy, not commit directly to this repo +- **Version compatibility**: The Terraform modules reference specific Psoxy release tags +- **AWS-specific**: This example is for AWS deployments; see `psoxy-example-gcp` for Google Cloud Platform +- **Security**: Users must configure authentication credentials and IAM permissions appropriately +- **Data sources**: Not all connectors are enabled by default; users customize based on their needs + +## Getting More Help + +- **Documentation**: [https://docs.worklytics.co/psoxy](https://docs.worklytics.co/psoxy) +- **Main Repository Issues**: [https://github.com/Worklytics/psoxy/issues](https://github.com/Worklytics/psoxy/issues) +- **Support**: [sales@worklytics.co](mailto:sales@worklytics.co) + diff --git a/check-prereqs b/check-prereqs index db63bcb..32886a4 100755 --- a/check-prereqs +++ b/check-prereqs @@ -7,26 +7,50 @@ printf "See https://github.com/Worklytics/psoxy#prerequisites for more informati HOMEBREW_AVAILABLE=`brew -v &> /dev/null` +CI_MODE=false +for arg in "$@"; do + if [[ "$arg" == "--ci" ]] || [[ "$arg" == "--non-interactive" ]]; then + CI_MODE=true + fi +done + # Source centralized color scheme source "$(dirname "$0")/set-term-colorscheme.sh" if ! git --version &> /dev/null ; then printf "${ERR}Git not installed.${NC} Not entirely sure how you got here without it, but to install see https://git-scm.com/book/en/v2/Getting-Started-Installing-Git\n" if $HOMEBREW_AVAILABLE; then printf " or, as you have Homebrew available, run ${CODE}brew install git${NC}\n"; fi - exit 1 + if [[ "$CI_MODE" != "true" ]]; then + exit 1 + fi fi if ! terraform -v &> /dev/null ; then printf "${ERR}Terraform CLI not available.${NC} Psoxy examples / deployment scripts require it. See ${CODE}https://developer.hashicorp.com/terraform/downloads${NC} for installation options\n" - exit 1 + if [[ "$CI_MODE" != "true" ]]; then + exit 1 + fi +else + TF_VERSION_FULL=$(terraform -version | head -n 1) + TF_VERSION_MAJOR_MINOR=$(echo "$TF_VERSION_FULL" | sed -n 's/^Terraform v\([0-9]*\.[0-9]*\).*$/\1/p') + TF_MAJOR=$(echo "$TF_VERSION_MAJOR_MINOR" | cut -d. -f1) + TF_MINOR=$(echo "$TF_VERSION_MAJOR_MINOR" | cut -d. -f2) + if (( TF_MAJOR < 1 || (TF_MAJOR == 1 && TF_MINOR < 7) )); then + printf "${ERR}This Terraform version appears to be unsupported.${NC} Psoxy requires a supported version of Terraform 1.7 or later.\n" + printf "We recommend you upgrade. See https://developer.hashicorp.com/terraform/downloads\n" + else + printf "Your Terraform version is ${CODE}${TF_VERSION_FULL}${NC}.\n" + fi fi # Check Maven installation if ! mvn -v &> /dev/null ; then - printf "${WARN}Maven not installed.${NC} It is REQUIRED unless you will use a pre-built JAR. To install, see https://maven.apache.org/install.html\n" + printf "${WARN}Maven not installed.${NC} It is REQUIRED unless you will use a pre-built JAR.\n" + printf " Note: Java JDK and Maven are only needed if building and bundling the java from source.\n" + printf " To install Maven, see https://maven.apache.org/install.html\n" if $HOMEBREW_AVAILABLE; then printf " or, as you have Homebrew available, run ${CODE}brew install maven${NC}\n"; fi - printf " (Using a prebuilt jar requires adding ${CODE}deployment_bundle=""${NC} to your ${CODE}terraform.tfvars${NC} file, and filling with s3/gcs uri for your desired JAR)\n" + printf " (Using a prebuilt jar requires adding ${CODE}deployment_bundle=""${NC} to your ${CODE}terraform.tfvars${NC} file, and filling with s3/gcs uri for your desired JAR. The JRE of your host platform (AWS/GCP) will still be used at runtime).\n" else MVN_VERSION=`mvn -v | grep "Apache Maven"` MVN_VERSION_MAJOR_MINOR=$(echo $MVN_VERSION | sed -n 's/^Apache Maven \([0-9]*\.[0-9]*\).*$/\1/p') @@ -49,9 +73,9 @@ else printf "Your Maven installation uses ${CODE}${JAVA_VERSION}${NC}.\n" - if [[ "$JAVA_VERSION_MAJOR" != 17 && "$JAVA_VERSION_MAJOR" != 21 && "$JAVA_VERSION_MAJOR" != 23 && "$JAVA_VERSION_MAJOR" != 24 ]]; then - printf "${ERR}This Java version appears to be unsupported. You should upgrade it, or may have compile errors.${NC} Psoxy requires an Oracle-supported version of Java 17 or later; as of April 2025, this includes Java 17, 21, or 24. See https://maven.apache.org/install.html\n" - if $HOMEBREW_AVAILABLE; then printf "or as you have Homebrew available, run ${CODE}brew install openjdk@17${NC}\n"; fi + if [[ "$JAVA_VERSION_MAJOR" != 21 && "$JAVA_VERSION_MAJOR" != 25 && "$JAVA_VERSION_MAJOR" != 26 ]]; then + printf "${ERR}This Java version appears to be unsupported. You should upgrade it, or may have compile errors.${NC} Psoxy requires an Oracle-supported version of Java 21 or later; as of March 2026, this includes Java 21, 25, and 26. See https://maven.apache.org/install.html\n" + if $HOMEBREW_AVAILABLE; then printf "or as you have Homebrew available, run ${CODE}brew install openjdk@21${NC}\n"; fi printf "If you have an alternative JDK installed, then you must update your ${CODE}JAVA_HOME${NC} environment variable to point to it.\n" fi @@ -87,6 +111,30 @@ else printf "AWS CLI version ${CODE}`aws --version`${NC} is installed.\n" printf "" printf "\t- make sure ${CODE}aws sts get-caller-identity${NC} returns the user/role/account you expect. $AWSCLI_REASON\n" + + if aws sts get-caller-identity &> /dev/null; then + AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text 2>/dev/null) + # the || true ensures that we fail silently even if set -e is on, and the 2>/dev/null handles standard error + AWS_CONCURRENCY=$(aws lambda get-account-settings --query 'AccountLimit.ConcurrentExecutions' --output text 2>/dev/null || true) + if [[ -n "$AWS_CONCURRENCY" && "$AWS_CONCURRENCY" =~ ^[0-9]+$ ]]; then + if (( AWS_CONCURRENCY < 1000 )); then + printf "\t- ${WARN}Warning: AWS Lambda account-level concurrency quota for account $AWS_ACCOUNT_ID is $AWS_CONCURRENCY, which is < 1000.${NC}\n" + printf "\t If this is the AWS account to which your lambda instances will be deployed, ensure that this amount is sufficient for your use case (we recommend at least 100).\n" + else + printf "\t- AWS Lambda account-level concurrency quota for account ${CODE}${AWS_ACCOUNT_ID}${NC} is ${CODE}${AWS_CONCURRENCY}${NC}.\n" + fi + fi + + # Check for IAM Role quotas + AWS_IAM_ROLES_QUOTA=$(aws service-quotas get-service-quota --service-code iam --quota-code L-FE177D64 --query 'Quota.Value' --output text 2>/dev/null || true) + if [[ -n "$AWS_IAM_ROLES_QUOTA" && "$AWS_IAM_ROLES_QUOTA" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then + AWS_IAM_ROLES_QUOTA=${AWS_IAM_ROLES_QUOTA%.*} # truncate decimals + printf "\t- AWS IAM Roles quota for account ${CODE}${AWS_ACCOUNT_ID}${NC} is ${CODE}${AWS_IAM_ROLES_QUOTA}${NC}.\n" + if (( AWS_IAM_ROLES_QUOTA < 1000 )); then + printf "\t ${WARN}Warning: you may need a higher limit if deploying many Psoxy instances.${NC}\n" + fi + fi + fi fi printf "\n" @@ -99,6 +147,18 @@ if ! gcloud --version &> /dev/null ; then else printf "Google Cloud SDK version ${CODE}`gcloud --version 2> /dev/null | head -n 1`${NC} is installed.\n" printf "\t- make sure ${CODE}gcloud auth list --filter=\"status:ACTIVE\"${NC} returns the account you expect. $GCLOUD_REASON\n" + + if gcloud auth list --filter="status:ACTIVE" --format="value(account)" 2>/dev/null | grep -q '@'; then + GCP_PROJECT_ID=$(gcloud config get-value project 2>/dev/null || true) + if [[ -n "$GCP_PROJECT_ID" ]]; then + # Check Cloud Functions Quota + GCP_FUNCTIONS_QUOTA=$(gcloud compute project-info describe --project="$GCP_PROJECT_ID" --format="value(quotas.value)" --flatten="quotas[]" --filter="quotas.metric:CLOUD_FUNCTIONS_API_REQUESTS_PER_100_SECONDS" 2>/dev/null || true) + if [[ -n "$GCP_FUNCTIONS_QUOTA" && "$GCP_FUNCTIONS_QUOTA" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then + GCP_FUNCTIONS_QUOTA=${GCP_FUNCTIONS_QUOTA%.*} # truncate decimals + printf "\t- GCP Cloud Functions (per 100s) quota for project ${CODE}${GCP_PROJECT_ID}${NC} is ${CODE}${GCP_FUNCTIONS_QUOTA}${NC}.\n" + fi + fi + fi fi printf "\n" diff --git a/google-workspace-variables.tf b/google-workspace-variables.tf index 7d64a01..8ceca1f 100644 --- a/google-workspace-variables.tf +++ b/google-workspace-variables.tf @@ -27,7 +27,7 @@ variable "google_workspace_sa_to_impersonate" { variable "google_workspace_terraform_principal_email" { type = string - description = "Email of GCP principal that will be used to provision GCP resources via impersonation. Leave 'null' to use application default for you environment." + description = "Email of the principal (human user or service account) actively running Terraform. Used internally to grant this runner identity access to newly provisioned resources (like buckets/secrets). This is your 'true identity', distinct from `google_workspace_sa_to_impersonate` which is the identity Terraform assumes to create resources." default = null validation { @@ -38,25 +38,25 @@ variable "google_workspace_terraform_principal_email" { variable "google_workspace_example_user" { type = string - description = "user to impersonate for Google Workspace API calls (null for none)" + description = "[DEPRECATED - use map instead] user to impersonate for Google Workspace API calls (null for none)" default = null } variable "google_workspace_example_admin" { type = string - description = "user to impersonate for Google Workspace API calls (null for value of `google_workspace_example_user`)" + description = "[DEPRECATED - use map instead] user to impersonate for Google Workspace API calls (null for value of `google_workspace_example_user`)" default = null # will failover to user } variable "google_workspace_provision_keys" { type = bool - description = "whether to provision key for each Google Workspace connector's GCP Service Account (OAuth Client). If false, you must create the key manually and provide it." + description = "[DEPRECATED - use map instead] whether to provision key for each Google Workspace connector's GCP Service Account (OAuth Client). If false, you must create the key manually and provide it." default = true } variable "google_workspace_key_rotation_days" { type = number - description = "rotation period for the GCP Service Account keys, in days; not applicable if provision_gcp_sa_keys is false" + description = "[DEPRECATED - use map instead] rotation period for the GCP Service Account keys, in days; not applicable if provision_gcp_sa_keys is false" default = 60 validation { @@ -76,3 +76,10 @@ locals { ? local.validate_google_workspace_gcp_project_id_message : "")) } + + +variable "google_workspace_connector_settings" { + type = map(any) + description = "Map of configuration settings specifically for Google Workspace connectors (e.g. example users). Note that provider-controlling parameters (like GCP project IDs or impersonation SAs) remain top-level variables." + default = {} +} diff --git a/google-workspace.tf b/google-workspace.tf index c8e6970..646cdff 100644 --- a/google-workspace.tf +++ b/google-workspace.tf @@ -2,12 +2,14 @@ provider "google" { alias = "google_workspace" project = var.google_workspace_gcp_project_id - impersonate_service_account = var.google_workspace_sa_to_impersonate != null ? var.google_workspace_sa_to_impersonate : var.google_workspace_terraform_sa_account_email # TODO: remove ternary in 0.6.x + impersonate_service_account = var.google_workspace_sa_to_impersonate } module "worklytics_connectors_google_workspace" { - source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-google-workspace?ref=v0.5.18" + source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-google-workspace?ref=v0.6.0" + + google_workspace_connector_settings = var.google_workspace_connector_settings providers = { @@ -15,6 +17,7 @@ module "worklytics_connectors_google_workspace" { } environment_id = var.environment_name + base_dir = var.psoxy_base_dir enabled_connectors = var.enabled_connectors gcp_project_id = var.google_workspace_gcp_project_id tf_gcp_principal_email = var.google_workspace_terraform_principal_email diff --git a/init b/init index c49e2a0..c82feb3 100755 --- a/init +++ b/init @@ -1,5 +1,9 @@ #!/bin/bash +# Use a local Azure CLI config directory if present to avoid conflicts with other Azure tenants +if [ -d "${PWD}/.azure" ]; then + export AZURE_CONFIG_DIR="${PWD}/.azure" +fi # Psoxy init script - lite version # # Usage: @@ -57,12 +61,41 @@ if [[ -z "$EXPLICIT_REPO_CLONE_DIR" ]]; then exit 1 fi else - # append trailing slash if not present - if [[ "${EXPLICIT_REPO_CLONE_DIR}" != */ ]]; then - EXPLICIT_REPO_CLONE_DIR="${EXPLICIT_REPO_CLONE_DIR}/" + # Walk up from the given path to find the repo root (identified by tools/init-example-full.sh) + CANDIDATE="$EXPLICIT_REPO_CLONE_DIR" + # strip trailing slash for consistent dirname handling + CANDIDATE="${CANDIDATE%/}" + # normalize to an absolute path so dirname traversal always makes progress toward / + if [[ -d "$CANDIDATE" ]]; then + CANDIDATE="$(cd "$CANDIDATE" 2>/dev/null && pwd -P)" + else + CANDIDATE_PARENT="$(dirname "$CANDIDATE")" + CANDIDATE_BASENAME="$(basename "$CANDIDATE")" + CANDIDATE="$(cd "$CANDIDATE_PARENT" 2>/dev/null && printf "%s/%s" "$(pwd -P)" "$CANDIDATE_BASENAME")" + fi + + FOUND_REPO_ROOT="" + while [[ -n "$CANDIDATE" ]] && [[ "$CANDIDATE" != "/" ]]; do + if [[ -f "${CANDIDATE}/tools/init-example-full.sh" ]]; then + FOUND_REPO_ROOT="$CANDIDATE" + break + fi + NEXT_CANDIDATE="$(dirname "$CANDIDATE")" + if [[ "$NEXT_CANDIDATE" == "$CANDIDATE" ]]; then + break + fi + CANDIDATE="$NEXT_CANDIDATE" + done + + if [[ -z "$FOUND_REPO_ROOT" ]]; then + printf "${ERR}Could not find repo root (tools/init-example-full.sh) at or above: ${EXPLICIT_REPO_CLONE_DIR}${NC}\n" + printf "Pass the path to the root of a clone of https://github.com/Worklytics/psoxy as the first argument.\n" + printf " eg ${CODE}./init ~/code/psoxy${NC}\n" + exit 1 fi - REPO_CLONE_BASE_DIR="$EXPLICIT_REPO_CLONE_DIR" + # append trailing slash + REPO_CLONE_BASE_DIR="${FOUND_REPO_ROOT}/" fi # pass control to the full init script. diff --git a/main.tf b/main.tf index 147942b..a38a374 100644 --- a/main.tf +++ b/main.tf @@ -1,11 +1,11 @@ terraform { - required_version = ">= 1.3, < 2.0" + required_version = "~> 1.7" required_providers { # for the infra that will host Psoxy instances aws = { source = "hashicorp/aws" - version = "~> 4.22" + version = "~> 6.0" } } @@ -20,15 +20,18 @@ terraform { # general cases module "worklytics_connectors" { - source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors?ref=v0.5.18" + source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors?ref=v0.6.0" enabled_connectors = var.enabled_connectors + connector_settings = var.connector_settings + base_dir = var.psoxy_base_dir chat_gpt_enterprise_example_workspace_id = var.chat_gpt_enterprise_example_workspace_id confluence_example_cloud_id = var.confluence_example_cloud_id confluence_example_group_id = var.confluence_example_group_id jira_cloud_id = var.jira_cloud_id jira_server_url = var.jira_server_url jira_example_issue_id = var.jira_example_issue_id + atlassian_organization_id = var.atlassian_organization_id salesforce_domain = var.salesforce_domain github_api_host = var.github_api_host github_enterprise_server_host = var.github_enterprise_server_host @@ -37,6 +40,9 @@ module "worklytics_connectors" { github_copilot_installation_id = var.github_copilot_installation_id github_organization = var.github_organization github_example_repository = var.github_example_repository + gitlab_url = var.gitlab_url + gitlab_example_group_id = var.gitlab_example_group_id + gitlab_example_project_id = var.gitlab_example_project_id gong_instance_subdomain = var.gong_instance_subdomain glean_instance_subdomain = var.glean_instance_subdomain salesforce_example_account_id = var.salesforce_example_account_id @@ -105,7 +111,7 @@ locals { } module "psoxy" { - source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-host?ref=v0.5.18" + source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-host?ref=v0.6.0" environment_name = var.environment_name aws_account_id = var.aws_account_id @@ -123,6 +129,7 @@ module "psoxy" { pseudonymize_app_ids = var.pseudonymize_app_ids email_canonicalization = var.email_canonicalization general_environment_variables = var.general_environment_variables + new_relic_account_id = var.new_relic_account_id function_env_kms_key_arn = var.project_aws_kms_key_arn logs_kms_key_arn = var.project_aws_kms_key_arn log_retention_days = var.log_retention_days @@ -178,7 +185,7 @@ locals { module "connection_in_worklytics" { for_each = local.all_instances - source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-psoxy-connection-aws?ref=v0.5.18" + source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-proxy-connection-aws?ref=v0.6.0" proxy_instance_id = each.key worklytics_host = var.worklytics_host diff --git a/misc-data-source-variables.tf b/misc-data-source-variables.tf index 68b9fef..631aa88 100644 --- a/misc-data-source-variables.tf +++ b/misc-data-source-variables.tf @@ -4,44 +4,50 @@ variable "chat_gpt_enterprise_example_workspace_id" { type = string - description = "Workspace id to use for example calls" + description = "[DEPRECATED - use connector_settings map instead] Workspace id to use for example calls" default = null } variable "confluence_example_cloud_id" { type = string default = null - description = "(Only required if using Confluence Cloud connector) Example of cloud id of the Confluence Cloud to connect to (ex: 1324a887-45db-1bf4-1e99-ef0ff456d421)." + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Confluence Cloud connector) Example of cloud id of the Confluence Cloud to connect to (ex: 1324a887-45db-1bf4-1e99-ef0ff456d421)." } variable "confluence_example_group_id" { type = string default = null - description = "(Only required if using Confluence Cloud connector) Example of group id of the Confluence Cloud to connect to (ex: 35e417ad-bcb1-45fe-9be0-959239a84327)." + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Confluence Cloud connector) Example of group id of the Confluence Cloud to connect to (ex: 35e417ad-bcb1-45fe-9be0-959239a84327)." } variable "salesforce_domain" { type = string - description = "Domain of the Salesforce to connect to (only required if using Salesforce connector). To find your My Domain URL, from Setup, in the Quick Find box, enter My Domain, and then select My Domain" + description = "[DEPRECATED - use connector_settings map instead] Domain of the Salesforce to connect to (only required if using Salesforce connector). To find your My Domain URL, from Setup, in the Quick Find box, enter My Domain, and then select My Domain" default = "" } variable "jira_server_url" { type = string default = null - description = "(Only required if using Jira Server connector) URL of the Jira server (ex: myjiraserver.mycompany.com)" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Jira Server connector) URL of the Jira server (ex: myjiraserver.mycompany.com)" } variable "jira_cloud_id" { type = string default = null - description = "(Only required if using Jira Cloud connector) Cloud id of the Jira Cloud to connect to (ex: 1324a887-45db-1bf4-1e99-ef0ff456d421)." + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Jira Cloud connector) Cloud id of the Jira Cloud to connect to (ex: 1324a887-45db-1bf4-1e99-ef0ff456d421)." } variable "jira_example_issue_id" { type = string default = null - description = "If using Jira Server/Cloud connector, provide id of an issue for only to be used as part of example calls for Jira (ex: ETV-12)" + description = "[DEPRECATED - use connector_settings map instead] If using Jira Server/Cloud connector, provide id of an issue for only to be used as part of example calls for Jira (ex: ETV-12)" +} + +variable "atlassian_organization_id" { + type = string + default = null + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Atlassian Organization connector) ID of the Atlassian Organization (ex: 1324a887-45db-1bf4-1e99-ef0ff456d421)" } # DEPRECATED @@ -54,60 +60,78 @@ variable "github_api_host" { variable "github_enterprise_server_host" { type = string default = "" - description = "(Only required if using Github Enterprise Server connector) Host of the Github instance (ex: github.mycompany.com)." + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Github Enterprise Server connector) Host of the Github instance (ex: github.mycompany.com)." } variable "github_enterprise_server_version" { type = string default = "v3" - description = "(Only required if using Github Enterprise Server connector) Version of the server to use (ex: v3). By default, v3" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Github Enterprise Server connector) Version of the server to use (ex: v3). By default, v3" } variable "github_installation_id" { type = string default = null - description = "(Only required if using Github connector) InstallationId of the application in your org for authentication with the proxy instance (ex: 123456)" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Github connector) InstallationId of the application in your org for authentication with the proxy instance (ex: 123456)" } variable "github_copilot_installation_id" { type = string default = null - description = "(Only required if using Github Copilot connector) InstallationId of the application in your org for authentication with the proxy instance (ex: 123456)" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Github Copilot connector) InstallationId of the application in your org for authentication with the proxy instance (ex: 123456)" } variable "github_organization" { type = string default = null - description = "(Only required if using Github connector) Name of the organization to be used as part of example calls for Github (ex: Worklytics). NOTE: If using Enterprise Server, this can be a list of organizations split by commas (ex: Worklytics,Worklytics2)" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Github connector) Name of the organization to be used as part of example calls for Github (ex: Worklytics). NOTE: If using Enterprise Server, this can be a list of organizations split by commas (ex: Worklytics,Worklytics2)" } variable "github_example_repository" { type = string default = null - description = "(Only required if using Github connector) Name for the repository to be used as part of example calls for Github (ex: psoxy)" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Github connector) Name for the repository to be used as part of example calls for Github (ex: psoxy)" +} + +variable "gitlab_url" { + type = string + default = "https://gitlab.com" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using GitLab Managed connector) URL of the GitLab instance (ex: https://gitlab.mycompany.com, https://mycompany.com/gitlab, https://my-instance-gitlab.com, etc)" +} + +variable "gitlab_example_group_id" { + type = string + default = null + description = "[DEPRECATED - use connector_settings map instead] (Only required if using GitLab connector) Example group ID for test API calls (ex: 12345)" +} + +variable "gitlab_example_project_id" { + type = string + default = null + description = "[DEPRECATED - use connector_settings map instead] (Only required if using GitLab connector) Example project ID for test API calls (ex: 12345)" } variable "glean_instance_subdomain" { type = string default = null - description = "(Only required if using Glean connector) Subdomain of your Glean instance (ex: if your Glean URL is 'acme-be.glean.com', the instance subdomain is 'acme-be')" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Glean connector) Subdomain of your Glean instance (ex: if your Glean URL is 'acme-be.glean.com', the instance subdomain is 'acme-be')" } variable "gong_instance_subdomain" { type = string default = null - description = "(Only required if using Gong connector) Subdomain of your Gong instance (ex: if your Gong URL is 'acme.gong.io', the instance subdomain is 'acme')" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Gong connector) Subdomain of your Gong instance (ex: if your Gong URL is 'acme.gong.io', the instance subdomain is 'acme')" } variable "salesforce_example_account_id" { type = string default = null - description = "(Only required if using Salesforce connector) Id of the account id for usign as an example calls for Salesforce (ex: 0015Y00002c7g95QAA)" + description = "[DEPRECATED - use connector_settings map instead] (Only required if using Salesforce connector) Id of the account id for usign as an example calls for Salesforce (ex: 0015Y00002c7g95QAA)" } locals { # tflint-ignore: terraform_unused_declarations - validate_salesforce_domain = (var.salesforce_domain == null || var.salesforce_domain == "" || can(regex(":|\\/", try(var.salesforce_domain, "")))) && contains(var.enabled_connectors, "salesforce") + validate_salesforce_domain = (try(var.connector_settings["salesforce_domain"], var.salesforce_domain) == null || try(var.connector_settings["salesforce_domain"], var.salesforce_domain) == "" || can(regex(":|\\/", try(try(var.connector_settings["salesforce_domain"], var.salesforce_domain), "")))) && contains(var.enabled_connectors, "salesforce") validate_salesforce_domain_message = "The salesforce_domain var should be populated and to be with only the domain without protocol or query paths if enabled." validate_salesforce_domain_check = regex( "^${local.validate_salesforce_domain_message}$", @@ -115,7 +139,7 @@ locals { ? local.validate_salesforce_domain_message : "")) - validate_github_enterprise_server_host = (var.github_api_host == null && (var.github_enterprise_server_host == null || var.github_enterprise_server_host == "" || can(regex(":|\\/", try(var.github_enterprise_server_host, ""))))) && contains(var.enabled_connectors, "github-enterprise-server") + validate_github_enterprise_server_host = (try(var.connector_settings["github_api_host"], var.github_api_host) == null && (try(var.connector_settings["github_enterprise_server_host"], var.github_enterprise_server_host) == null || try(var.connector_settings["github_enterprise_server_host"], var.github_enterprise_server_host) == "" || can(regex(":|\\/", try(try(var.connector_settings["github_enterprise_server_host"], var.github_enterprise_server_host), ""))))) && contains(var.enabled_connectors, "github-enterprise-server") validate_github_enterprise_server_host_message = "The github_enterprise_server_host var should be populated and to be with only the domain without protocol or query paths if GitHub Enterprise Server is enabled." validate_github_enterprise_server_host_check = regex( "^${local.validate_github_enterprise_server_host_message}$", @@ -123,8 +147,15 @@ locals { ? local.validate_github_enterprise_server_host_message : "")) + validate_gitlab_managed_url = !can(regex("^https://", try(try(var.connector_settings["gitlab_url"], var.gitlab_url), ""))) && contains(var.enabled_connectors, "gitlab-managed") + validate_gitlab_managed_url_message = "The gitlab_url var should be populated with HTTPS protocol if GitLab Managed is enabled." + validate_gitlab_managed_url_check = regex( + "^${local.validate_gitlab_managed_url_message}$", + (!local.validate_gitlab_managed_url + ? local.validate_gitlab_managed_url_message + : "")) - validate_glean_instance_subdomain = (var.glean_instance_subdomain == null || var.glean_instance_subdomain == "") && contains(var.enabled_connectors, "glean") + validate_glean_instance_subdomain = (try(var.connector_settings["glean_instance_subdomain"], var.glean_instance_subdomain) == null || try(var.connector_settings["glean_instance_subdomain"], var.glean_instance_subdomain) == "") && contains(var.enabled_connectors, "glean") validate_glean_instance_subdomain_message = "The glean_instance_subdomain var should be populated if Glean connector is enabled." validate_glean_instance_subdomain_check = regex( "^${local.validate_glean_instance_subdomain_message}$", @@ -132,7 +163,7 @@ locals { ? local.validate_glean_instance_subdomain_message : "")) - validate_gong_instance_subdomain = (var.gong_instance_subdomain == null || var.gong_instance_subdomain == "") && contains(var.enabled_connectors, "gong-metrics") + validate_gong_instance_subdomain = (try(var.connector_settings["gong_instance_subdomain"], var.gong_instance_subdomain) == null || try(var.connector_settings["gong_instance_subdomain"], var.gong_instance_subdomain) == "") && contains(var.enabled_connectors, "gong-metrics") validate_gong_instance_subdomain_message = "The gong_instance_subdomain var should be populated if Gong connector is enabled." validate_gong_instance_subdomain_check = regex( "^${local.validate_gong_instance_subdomain_message}$", diff --git a/msft-365-variables.tf b/msft-365-variables.tf index 03dd92b..6a0791f 100644 --- a/msft-365-variables.tf +++ b/msft-365-variables.tf @@ -19,42 +19,48 @@ variable "msft_connector_app_object_id" { variable "example_msft_user_guid" { type = string - description = "example MSFT user guid (uuid) for test API calls (OPTIONAL)" + description = "[DEPRECATED - use map instead] example MSFT user guid (uuid) for test API calls (OPTIONAL)" default = "{EXAMPLE_MSFT_USER_GUID}" } variable "msft_teams_example_team_guid" { type = string - description = "example of MSFT Id (GUID) of a Teams Team for test API calls (OPTIONAL)" + description = "[DEPRECATED - use map instead] example of MSFT Id (GUID) of a Teams Team for test API calls (OPTIONAL)" default = "{EXAMPLE_MSFT_TEAMS_TEAM_GUID}" } variable "msft_teams_example_channel_guid" { type = string - description = "example of MSFT Id (GUID) of a Teams Channel for test API calls (OPTIONAL)" + description = "[DEPRECATED - use map instead] example of MSFT Id (GUID) of a Teams Channel for test API calls (OPTIONAL)" default = "{EXAMPLE_MSFT_TEAMS_CHANNEL_GUID}" } variable "msft_teams_example_chat_guid" { type = string - description = "example of MSFT Id (GUID) of a Teams Chat for test API calls (OPTIONAL)" + description = "[DEPRECATED - use map instead] example of MSFT Id (GUID) of a Teams Chat for test API calls (OPTIONAL)" default = "{EXAMPLE_MSFT_TEAMS_CHAT_GUID}" } variable "msft_teams_example_call_guid" { type = string - description = "example of MSFT Id (GUID) of a Teams Call for test API calls (OPTIONAL)" + description = "[DEPRECATED - use map instead] example of MSFT Id (GUID) of a Teams Call for test API calls (OPTIONAL)" default = "{EXAMPLE_MSFT_TEAMS_CALL_GUID}" } variable "msft_teams_example_call_record_guid" { type = string - description = "example of MSFT Id (GUID) of a Teams Call Record for test API calls (OPTIONAL)" + description = "[DEPRECATED - use map instead] example of MSFT Id (GUID) of a Teams Call Record for test API calls (OPTIONAL)" default = "{EXAMPLE_MSFT_TEAMS_CALL_RECORD_GUID}" } variable "msft_teams_example_online_meeting_join_url" { type = string - description = "example of an URL to join into an OnlineMeeting for test API calls (OPTIONAL)" + description = "[DEPRECATED - use map instead] example of an URL to join into an OnlineMeeting for test API calls (OPTIONAL)" default = "{EXAMPLE_MSFT_TEAMS_ONLINE_MEETING_URL}" -} \ No newline at end of file +} + +variable "msft_365_connector_settings" { + type = map(any) + description = "Map of configuration settings specifically for MSFT 365 connectors (e.g. test GUIDs, custom paths). Note that provider-controlling parameters (like msft_tenant_id or existing app IDs) remain top-level variables." + default = {} +} diff --git a/msft-365.tf b/msft-365.tf index d2a5ead..4b17a36 100644 --- a/msft-365.tf +++ b/msft-365.tf @@ -1,10 +1,13 @@ # BEGIN MSFT module "worklytics_connectors_msft_365" { - source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-msft-365?ref=v0.5.18" + source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-msft-365?ref=v0.6.0" + + msft_365_connector_settings = var.msft_365_connector_settings enabled_connectors = var.enabled_connectors + base_dir = var.psoxy_base_dir environment_id = var.environment_name msft_tenant_id = var.msft_tenant_id example_msft_user_guid = var.example_msft_user_guid @@ -47,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.5.18" + source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-cognito-pool?ref=v0.6.0" developer_provider_name = local.developer_provider_name name = "${local.env_qualifier}-azure-ad-federation" @@ -69,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.5.18" + source = "git::https://github.com/worklytics/psoxy//infra/modules/aws-cognito-identity-cli?ref=v0.6.0" aws_region = data.aws_region.current.id @@ -106,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.5.18" + source = "git::https://github.com/worklytics/psoxy//infra/modules/azuread-federated-credentials?ref=v0.6.0" application_id = each.value.connector_id display_name = "${local.env_qualifier}AccessFromAWS" diff --git a/variables.tf b/variables.tf index 0b19694..76c7897 100644 --- a/variables.tf +++ b/variables.tf @@ -36,6 +36,12 @@ variable "aws_region" { default = "us-east-1" } +variable "new_relic_account_id" { + type = string + description = "**beta** New Relic account ID to enable New Relic instrumentation. If set, this will auto-configure the NEW_RELIC_ACCOUNT_ID and NEW_RELIC_LAMBDA_HANDLER environment variables for proxied lambdas." + default = null +} + variable "iam_roles_permissions_boundary" { type = string description = "*beta* ARN of the permissions boundary to attach to IAM roles created by this module." @@ -268,7 +274,17 @@ variable "custom_api_connectors" { })) description = "map of custom API connectors to provision" - default = {} + default = { + # "custom-api" = { + # source_kind = "my-custom-api" + # source_auth_strategy = "bearer" + # target_host = "api.example.com" + # example_api_calls = ["/v1/users"] + # secured_variables = [ + # { name = "API_KEY" } + # ] + # } + } } variable "custom_api_connector_rules" { @@ -317,6 +333,7 @@ variable "custom_bulk_connectors" { memory_size_mb = optional(number, null) settings_to_provide = optional(map(string), {}) example_file = optional(string) + example_files = optional(list(string), []) })) description = "specs of custom bulk connectors to create" @@ -463,3 +480,9 @@ variable "todos_as_local_files" { description = "whether to render TODOs as flat files" default = true } + +variable "connector_settings" { + type = map(string) + default = {} + description = "Connector-specific settings." +}