Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
344 changes: 338 additions & 6 deletions docs/development.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions tests/terraform/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.terraform/
.terraform.lock.hcl
terraform.tfstate
terraform.tfstate.backup
kubeconfig-*
*.tfplan
75 changes: 75 additions & 0 deletions tests/terraform/wif/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# WIF Testing Terraform

Terraform configurations for provisioning cloud infrastructure to test Workload Identity Federation (WIF) with the Mondoo Operator.

Each subdirectory creates a **management cluster** (where the operator runs) and a **target cluster** (to be scanned), along with the IAM/RBAC plumbing needed for WIF authentication.

## Prerequisites

- [Terraform](https://developer.hashicorp.com/terraform/install) >= 1.3
- Cloud provider CLI authenticated:
- **GKE**: `gcloud auth application-default login`
- **EKS**: `aws configure` or environment variables
- **AKS**: `az login`

## Usage

Each provider is independent. Navigate to the desired directory and run:

```bash
cd gke/ # or eks/ or aks/
terraform init
terraform plan
terraform apply
```

After `apply` completes, check the outputs for the `mondoo_audit_config_snippet` which shows the exact YAML to use in your `MondooAuditConfig`.

```bash
terraform output mondoo_audit_config_snippet
```

## Providers

### GKE (`gke/`)

Creates two GKE Standard clusters with Workload Identity enabled. Sets up a Google Service Account with the necessary IAM bindings for the management cluster's KSA to authenticate to the target cluster.

**Required variables:**
- `project_id` - GCP project ID

**Post-apply manual step:** Create a `ClusterRoleBinding` on the target cluster granting the GSA read access (shown in outputs).

### GKE Autopilot (`gke-autopilot/`)

Same as GKE but uses Autopilot clusters. Autopilot clusters have Workload Identity enabled by default and manage node pools automatically.

**Required variables:**
- `project_id` - GCP project ID

**Post-apply manual step:** Create a `ClusterRoleBinding` on the target cluster granting the GSA read access (shown in outputs).

### EKS (`eks/`)

Creates two EKS clusters in a shared VPC with IRSA (IAM Roles for Service Accounts) configured. Sets up an IAM role with a trust policy for the management cluster's OIDC provider and maps it into the target cluster's `aws-auth` ConfigMap.

**Required variables:** None (uses defaults)

### AKS (`aks/`)

Creates two AKS clusters with Azure Workload Identity configured. Sets up an Azure AD application with a federated identity credential and grants it RBAC on the target cluster.

**Required variables:** None (uses defaults)

## Cleanup

```bash
terraform destroy
```

## Design Notes

- Spot/preemptible instances are used for cost savings
- Random 4-character suffixes ensure unique resource names
- Terraform state is stored locally (not in a remote backend)
- These configs are for manual developer testing, not CI
124 changes: 124 additions & 0 deletions tests/terraform/wif/aks/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
resource "random_string" "suffix" {
length = 4
special = false
upper = false
}

locals {
name_prefix = "mondoo-wif-${random_string.suffix.result}"
}

data "azurerm_subscription" "current" {}
data "azurerm_client_config" "current" {}

################################################################################
# Resource Group
################################################################################

resource "azurerm_resource_group" "rg" {
name = "${local.name_prefix}-rg"
location = var.location

tags = {
Environment = "Mondoo Operator WIF Tests"
}
}

################################################################################
# Management Cluster (runs the operator, OIDC + Workload Identity enabled)
################################################################################

resource "azurerm_kubernetes_cluster" "management" {
name = "${local.name_prefix}-mgmt"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
dns_prefix = "${local.name_prefix}-mgmt"
kubernetes_version = var.k8s_version

oidc_issuer_enabled = true
workload_identity_enabled = true

default_node_pool {
name = "default"
node_count = 1
vm_size = "Standard_D2s_v3"
}

identity {
type = "SystemAssigned"
}

tags = {
Environment = "Mondoo Operator WIF Tests"
}
}

################################################################################
# Target Cluster (to be scanned, Azure RBAC enabled)
################################################################################

resource "azurerm_kubernetes_cluster" "target" {
name = "${local.name_prefix}-target"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
dns_prefix = "${local.name_prefix}-target"
kubernetes_version = var.k8s_version

azure_active_directory_role_based_access_control {
managed = true
azure_rbac_enabled = true
}

default_node_pool {
name = "default"
node_count = 1
vm_size = "Standard_D2s_v3"
}

identity {
type = "SystemAssigned"
}

tags = {
Environment = "Mondoo Operator WIF Tests"
}
}

################################################################################
# Azure AD Application + Service Principal for the scanner
################################################################################

resource "azuread_application" "scanner" {
display_name = "${local.name_prefix}-scanner"
}

resource "azuread_service_principal" "scanner" {
client_id = azuread_application.scanner.client_id
}

# Federated identity credential: links the management cluster's KSA to the Azure AD app
resource "azuread_application_federated_identity_credential" "scanner" {
application_id = azuread_application.scanner.id
display_name = "mondoo-operator-wif"
audiences = ["api://AzureADTokenExchange"]
issuer = azurerm_kubernetes_cluster.management.oidc_issuer_url
subject = "system:serviceaccount:${var.scanner_namespace}:${var.scanner_service_account}"
}

################################################################################
# Role Assignments on the target cluster
################################################################################

# Allow the service principal to get cluster credentials
resource "azurerm_role_assignment" "cluster_user" {
scope = azurerm_kubernetes_cluster.target.id
role_definition_name = "Azure Kubernetes Service Cluster User Role"
principal_id = azuread_service_principal.scanner.object_id
}

# Allow the service principal to read K8s resources via Azure RBAC
resource "azurerm_role_assignment" "rbac_reader" {
scope = azurerm_kubernetes_cluster.target.id
role_definition_name = "Azure Kubernetes Service RBAC Reader"
principal_id = azuread_service_principal.scanner.object_id
}
56 changes: 56 additions & 0 deletions tests/terraform/wif/aks/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
output "subscription_id" {
description = "Azure subscription ID."
value = data.azurerm_subscription.current.subscription_id
}

output "tenant_id" {
description = "Azure AD tenant ID."
value = data.azurerm_client_config.current.tenant_id
}

output "client_id" {
description = "Azure AD application (client) ID for the scanner."
value = azuread_application.scanner.client_id
}

output "resource_group" {
description = "Resource group containing both clusters."
value = azurerm_resource_group.rg.name
}

output "management_cluster_name" {
description = "Name of the management AKS cluster."
value = azurerm_kubernetes_cluster.management.name
}

output "target_cluster_name" {
description = "Name of the target AKS cluster."
value = azurerm_kubernetes_cluster.target.name
}

output "mondoo_audit_config_snippet" {
description = "MondooAuditConfig YAML snippet for the AKS WIF external cluster."
value = <<-EOT
externalClusters:
- name: ${azurerm_kubernetes_cluster.target.name}
workloadIdentity:
provider: aks
aks:
subscriptionId: ${data.azurerm_subscription.current.subscription_id}
resourceGroup: ${azurerm_resource_group.rg.name}
clusterName: ${azurerm_kubernetes_cluster.target.name}
clientId: ${azuread_application.scanner.client_id}
tenantId: ${data.azurerm_client_config.current.tenant_id}
EOT
}

output "kubeconfig_commands" {
description = "Commands to configure kubectl for both clusters."
value = <<-EOT
# Management cluster:
az aks get-credentials --resource-group ${azurerm_resource_group.rg.name} --name ${azurerm_kubernetes_cluster.management.name} --context mgmt

# Target cluster:
az aks get-credentials --resource-group ${azurerm_resource_group.rg.name} --name ${azurerm_kubernetes_cluster.target.name} --context target
EOT
}
23 changes: 23 additions & 0 deletions tests/terraform/wif/aks/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
variable "location" {
description = "Azure region for all resources."
type = string
default = "eastus"
}

variable "k8s_version" {
description = "Kubernetes version for the AKS clusters."
type = string
default = "1.30"
}

variable "scanner_namespace" {
description = "Namespace where the Mondoo operator scanner runs."
type = string
default = "mondoo-operator"
}

variable "scanner_service_account" {
description = "Kubernetes ServiceAccount name used by the scanner."
type = string
default = "mondoo-client-wif-target"
}
24 changes: 24 additions & 0 deletions tests/terraform/wif/aks/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
terraform {
required_version = ">= 1.3"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
azuread = {
source = "hashicorp/azuread"
version = "~> 2.47"
}
random = {
source = "hashicorp/random"
version = "~> 3.5"
}
}
}

provider "azurerm" {
features {}
}

provider "azuread" {}
Loading
Loading