Skip to content
Open
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@ yarn-error.log*
*tfvars*
.terraform.lock.hcl
.env

# Generated assets
website/public/assets/building-block-logos/
website/public/assets/logos/
website/public/assets/*.json
135 changes: 135 additions & 0 deletions modules/oci/application-compartment/buildingblock/APP_TEAM_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# OCI Application Compartment

## Description
This building block creates a new Oracle Cloud Infrastructure (OCI) compartment and manages user access permissions. It provides application teams with a secure, isolated environment for deploying their workloads while ensuring proper access controls through IAM groups and policies.

## Usage Motivation
This building block is designed for application teams that need to:
- Create isolated OCI compartments for their applications
- Manage team access with appropriate permission levels
- Ensure compliance with organizational security policies
- Automate compartment setup and user onboarding
- Deploy workloads in the correct organizational structure based on landing zone and environment

## Usage Examples
- A development team creates a compartment for their microservices architecture with different access levels for developers, operators, and auditors.
- A platform team provisions compartments for multiple application teams with consistent access patterns across different landing zones.
- An organization sets up compartments for different environments (development, QA, test, production) within their cloud-native landing zone.
- A sandbox project gets provisioned with a simplified single-compartment setup for rapid prototyping.

## Shared Responsibility

| Responsibility | Platform Team | Application Team |
|------------------------|--------------|----------------|
| Provisioning and configuring compartments |||
| Managing user access and permissions |||
| Defining compartment naming conventions |||
| Monitoring compartment usage and costs |||
| Configuring landing zones and parent compartments |||
| Managing resources within the compartment |||

## Recommendations for Secure and Efficient Compartment Usage
- **Follow naming conventions**: Compartment names are automatically generated following organizational patterns.
- **Use appropriate landing zones**: Select the correct landing zone based on your application's security and compliance requirements.
- **Choose the right environment**: Properly tag your project with the correct environment (dev, qa, test, prod) for proper compartment placement.
- **Grant least privilege access**: Assign users the minimum permissions they need (reader < user < admin).
- **Regular access reviews**: Periodically review and update user permissions as team composition changes.
- **Resource organization**: Use the compartment to logically organize your cloud resources.
- **Cost tracking**: Leverage compartments for cost allocation and budgeting.

## Configuration Options

### How Compartment Placement Works

The building block automatically determines where to create your application compartment based on **meshStack project tags**:

1. **Landing Zone Tag**: Determines the overall security/compliance level
2. **Environment Tag**: Determines which environment-specific compartment to use (if applicable)

#### Landing Zone Types

##### Sandbox Landing Zone
- **Purpose**: For experimentation, learning, and rapid prototyping
- **Behavior**: All environments (dev, qa, test, prod) use the **same parent compartment**
- **Use Case**: Quick setup for non-production workloads

##### Cloud-Native Landing Zone
- **Purpose**: For production-ready applications with proper environment separation
- **Behavior**: Each environment gets its **own parent compartment**
- `dev` → Cloud-Native Dev compartment
- `qa` → Cloud-Native QA compartment
- `test` → Cloud-Native Test compartment
- `prod` → Cloud-Native Prod compartment
- **Use Case**: Production workloads requiring environment isolation

##### Fallback
- If no landing zone tags match, a default parent compartment is used

### User Roles and Permissions

Users can be assigned one or more roles from the authoritative system:

#### Reader Role
- **OCI Permissions**: Read-only access to all resources in the compartment
- **Use Case**: Auditors, stakeholders who need visibility but not modification rights

#### User Role
- **OCI Permissions**: Can manage:
- Compute instances (instance-family)
- Virtual networks (virtual-network-family)
- Block and boot volumes (volume-family)
- Object storage (object-family)
- Load balancers
- Read all resources
- **Use Case**: Developers and operators who need to deploy and manage applications

#### Admin Role
- **OCI Permissions**: Full management access to all resources in the compartment
- **Use Case**: Team leads, DevOps engineers who need complete control

**Note**: If a user has multiple roles, the highest privilege role takes precedence (admin > user > reader).

#### Example Scenarios

| Landing Zone Tag | Environment Tag | Result |
|-----------------|----------------|--------|
| `sandbox` | `dev` | Parent: Sandbox compartment (ignores environment) |
| `sandbox` | `prod` | Parent: Sandbox compartment (ignores environment) |
| `cloud-native` | `dev` | Parent: Cloud-Native Dev compartment |
| `cloud-native` | `prod` | Parent: Cloud-Native Prod compartment |
| No tags | Any | Parent: Default fallback Sandbox compartment |

### Automatic Compartment Naming

Compartments are automatically named following this pattern:
```
{foundation}-{workspace_id}-{project_id}
```

Example: `mycompany-platform-team-ecommerce-api`

The compartment description includes helpful context:
```
Application compartment for {workspace_id}/{project_id} [landing_zone/environment]
```

Example: `Application compartment for platform-team/ecommerce-api [cloud-native/prod]`

## What Gets Created

When you provision this building block, the following resources are created in OCI:

1. **Application Compartment**: A new compartment under the appropriate parent compartment
2. **Three IAM Groups**:
- `{compartment-name}-readers`: Read-only access group
- `{compartment-name}-users`: Standard user access group
- `{compartment-name}-admins`: Administrator access group
3. **Group Memberships**: Automatic assignment of users to groups based on their roles
4. **IAM Policy**: Access policies defining permissions for each group

## Outputs and Access

After provisioning, you'll receive:
- **Compartment OCID**: The unique identifier for your compartment
- **Console URL**: Direct link to access your compartment in the OCI Console
- **Group Information**: Names and OCIDs of the created IAM groups
209 changes: 209 additions & 0 deletions modules/oci/application-compartment/buildingblock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
---
name: OCI Application Compartment
supportedPlatforms:
- oci
description: |
Creates an application compartment with IAM groups and policies for team-based access control.
---

# OCI Application Compartment Building Block

Creates an application compartment with IAM groups and policies for team-based access control.

## Features

- **Application Compartment**: Creates a compartment for application workloads
- **Conditional Placement**: Places compartments based on meshStack project tags
- **Flexible Configuration**: Tag names and compartment mappings configurable via YAML
- **IAM Groups**: Three groups with different access levels (readers, users, admins)
- **Access Policies**: Granular permissions for each group

## Access Levels

### Readers
- Read-only access to all resources in the compartment

### Users
- Manage compute instances, storage, networking, and load balancers
- Read all resources

### Admins
- Full management access to all resources in the compartment

## Compartment Placement Logic

The module determines the parent compartment based on meshStack project tags configured in the `tag_relations` variable:

1. **Sandbox Landing Zone**: Always uses sandbox compartment, regardless of environment
2. **Cloud-Native Landing Zone**: Uses environment-specific compartments (dev/qa/test/prod)
3. **Fallback**: Uses default compartment if no tags match

## Usage

### Basic Usage

```hcl
module "application_compartment" {
source = "./application-compartment"
tenancy_ocid = var.tenancy_ocid
foundation = "my-foundation"
workspace_id = "my-workspace"
project_id = "my-project"
region = "eu-frankfurt-1"
users = var.users
}
```

The module uses default tag names (`Environment`, `landingzone_family`) and placeholder compartment IDs.

### Custom Configuration

Override the `tag_relations` variable to customize tag names and compartment mappings:

```hcl
module "application_compartment" {
source = "./application-compartment"
tenancy_ocid = var.tenancy_ocid
foundation = "my-foundation"
workspace_id = "my-workspace"
project_id = "my-project"
region = "eu-frankfurt-1"
users = var.users
tag_relations = <<-EOT
# meshStack tag names to read
tag_names:
environment: "Environment"
landing_zone: "landingzone_family"
# Landing zone configurations
landing_zones:
# Sandbox: single compartment for all environments
sandbox:
compartment_id: "ocid1.compartment.oc1..aaaaaaaa...sandbox"
# Cloud-native: per-environment compartments
cloud-native:
environments:
dev:
compartment_id: "ocid1.compartment.oc1..aaaaaaaa...cloudnative-dev"
qa:
compartment_id: "ocid1.compartment.oc1..aaaaaaaa...cloudnative-qa"
test:
compartment_id: "ocid1.compartment.oc1..aaaaaaaa...cloudnative-test"
prod:
compartment_id: "ocid1.compartment.oc1..aaaaaaaa...cloudnative-prod"
# Fallback if no match
default_compartment_id: "ocid1.compartment.oc1..aaaaaaaa...default"
EOT
}
```

## Configuration Structure

The `tag_relations` variable accepts YAML with the following structure:

```yaml
# Which meshStack tags to read
tag_names:
environment: "Environment" # Tag name for environment
landing_zone: "landingzone_family" # Tag name for landing zone family

# Compartment mappings per landing zone
# The landing zone names here match the values in your meshStack tags
landing_zones:
sandbox: # When landing_zone tag = "sandbox"
compartment_id: "ocid1.compartment..." # Single compartment (no environments)

cloud-native: # When landing_zone tag = "cloud-native"
environments: # Per-environment compartments
dev:
compartment_id: "ocid1.compartment..."
qa:
compartment_id: "ocid1.compartment..."
test:
compartment_id: "ocid1.compartment..."
prod:
compartment_id: "ocid1.compartment..."

# Default fallback compartment
default_compartment_id: "ocid1.compartment..."
```
**Important**:
- The keys under `landing_zones` (e.g., `sandbox`, `cloud-native`) must match the **values** in your meshStack `landingzone_family` tag
- Landing zones without an `environments` section will use the same compartment for all environments
- Landing zones with an `environments` section will route based on the environment tag value

## meshStack Integration

The module automatically:
1. Fetches project metadata from meshStack using `workspace_id` and `project_id`
2. Reads tags from the project (format: `map(list(string))`)
3. Extracts tag values based on `tag_names` configuration
4. Selects the appropriate compartment based on landing zone and environment

## Example Tag Scenarios

| meshStack Tags | Selected Compartment |
|----------------|---------------------|
| `landingzone_family: ["sandbox"]`, `Environment: ["dev"]` | `landing_zones.sandbox.compartment_id` |
| `landingzone_family: ["sandbox"]`, `Environment: ["prod"]` | `landing_zones.sandbox.compartment_id` |
| `landingzone_family: ["cloud-native"]`, `Environment: ["dev"]` | `landing_zones.cloud-native.environments.dev.compartment_id` |
| `landingzone_family: ["cloud-native"]`, `Environment: ["prod"]` | `landing_zones.cloud-native.environments.prod.compartment_id` |
| No matching tags | `default_compartment_id` |

<!-- BEGIN_TF_DOCS -->
## Requirements

No requirements.

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [oci_identity_compartment.application](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_compartment) | resource |
| [oci_identity_group.admins](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_group) | resource |
| [oci_identity_group.readers](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_group) | resource |
| [oci_identity_group.users](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_group) | resource |
| [oci_identity_policy.application](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_policy) | resource |
| [oci_identity_user_group_membership.admins](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_user_group_membership) | resource |
| [oci_identity_user_group_membership.readers](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_user_group_membership) | resource |
| [oci_identity_user_group_membership.users](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_user_group_membership) | resource |
| [meshstack_project.project](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/data-sources/project) | data source |
| [oci_identity_users.all_users](https://registry.terraform.io/providers/oracle/oci/latest/docs/data-sources/identity_users) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_foundation"></a> [foundation](#input\_foundation) | Foundation name prefix | `string` | n/a | yes |
| <a name="input_project_id"></a> [project\_id](#input\_project\_id) | Project identifier (e.g., application name) | `string` | n/a | yes |
| <a name="input_region"></a> [region](#input\_region) | OCI region identifier (e.g., eu-frankfurt-1, us-ashburn-1) | `string` | n/a | yes |
| <a name="input_tag_relations"></a> [tag\_relations](#input\_tag\_relations) | YAML configuration for tag-based compartment mapping | `string` | `"# meshStack tag names to read\ntag_names:\n environment: \"Environment\"\n landing_zone: \"landingzone_family\"\n\n# Landing zone configurations\nlanding_zones:\n # Sandbox: single compartment for all environments\n sandbox:\n compartment_id: \"ocid1.compartment.oc1..aaaaaaaa...sandbox\"\n\n # Cloud-native: per-environment compartments\n cloud-native:\n environments:\n dev:\n compartment_id: \"ocid1.compartment.oc1..aaaaaaaa...cloudnative-dev\"\n qa:\n compartment_id: \"ocid1.compartment.oc1..aaaaaaaa...cloudnative-qa\"\n test:\n compartment_id: \"ocid1.compartment.oc1..aaaaaaaa...cloudnative-test\"\n prod:\n compartment_id: \"ocid1.compartment.oc1..aaaaaaaa...cloudnative-prod\"\n\n# Fallback if no match\ndefault_compartment_id: \"ocid1.compartment.oc1..aaaaaaaa...default\"\n"` | no |
| <a name="input_tenancy_ocid"></a> [tenancy\_ocid](#input\_tenancy\_ocid) | OCID of the OCI tenancy | `string` | n/a | yes |
| <a name="input_users"></a> [users](#input\_users) | List of users from authoritative system | <pre>list(object({<br> meshIdentifier = string<br> username = string<br> firstName = string<br> lastName = string<br> email = string<br> euid = string<br> roles = list(string)<br> }))</pre> | `[]` | no |
| <a name="input_workspace_id"></a> [workspace\_id](#input\_workspace\_id) | Workspace identifier (e.g., team name or business unit) | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_admin_group_id"></a> [admin\_group\_id](#output\_admin\_group\_id) | OCID of the admins group |
| <a name="output_admin_group_name"></a> [admin\_group\_name](#output\_admin\_group\_name) | Name of the admins group |
| <a name="output_compartment_id"></a> [compartment\_id](#output\_compartment\_id) | OCID of the created application compartment |
| <a name="output_compartment_name"></a> [compartment\_name](#output\_compartment\_name) | Name of the created application compartment |
| <a name="output_console_url"></a> [console\_url](#output\_console\_url) | OCI Console URL for direct access to the compartment |
| <a name="output_policy_id"></a> [policy\_id](#output\_policy\_id) | OCID of the access policy |
| <a name="output_reader_group_id"></a> [reader\_group\_id](#output\_reader\_group\_id) | OCID of the readers group |
| <a name="output_reader_group_name"></a> [reader\_group\_name](#output\_reader\_group\_name) | Name of the readers group |
| <a name="output_user_group_id"></a> [user\_group\_id](#output\_user\_group\_id) | OCID of the users group |
| <a name="output_user_group_name"></a> [user\_group\_name](#output\_user\_group\_name) | Name of the users group |
<!-- END_TF_DOCS -->
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading