Skip to content
Back to skills

Oraclecloud Multi Env Setup

DSecurity

'Configure multi-environment OCI workflows with config profiles and compartment-per-environment

  • 2,719 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 21, 2026
ai-agentspythonshellbashrailsawsapidatabaseci/cd

Works with

  • claude code
  • cli
  • api

Security analysis

D55/100
  • criticalReads or references SSH private keys
  • criticalModifies startup scripts or system services for persistence
  • criticalModifies startup scripts or system services for persistence
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned September 21, 2026

npx -y skills add jeremylongshore/claude-code-plugins-plus --skill oraclecloud-multi-env-setup --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Oraclecloud Multi Env Setup?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Oraclecloud Multi Env Setup
[![Security: D — Skills Directory](https://www.skillsdirectory.com/api/skills/jeremylongshore-oraclecloud-multi-env-setup-4c8aa5f8/badge)](https://www.skillsdirectory.com/skills/jeremylongshore-oraclecloud-multi-env-setup-4c8aa5f8)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: oraclecloud-multi-env-setup
description: 'Configure multi-environment OCI workflows with config profiles and compartment-per-environment
  patterns.

  Use when setting up dev/staging/prod separation, switching between OCI profiles,
  or preventing accidental production deployments.

  Trigger with "oraclecloud multi env setup", "oci profiles", "oci environments",
  "oci config profiles".

  '
allowed-tools: Read, Write, Edit, Bash(pip:*), Bash(oci:*), Grep
version: 1.8.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
tags:
- saas
- oraclecloud
- oci
compatibility: Designed for Claude Code
---
# Oracle Cloud Multi-Environment Setup

## Overview

OCI has no "accounts" like AWS — you use compartments plus OCI config profiles for dev/staging/prod separation. But profile switching is manual, compartment OCIDs are easy to confuse, and one wrong `--compartment-id` deploys to production. This skill sets up safe multi-environment workflows with named profiles, compartment aliasing, environment validation, and deployment guardrails.

**Purpose:** Configure safe, repeatable multi-environment OCI workflows that prevent accidental cross-environment operations.

## Prerequisites

- **OCI Python SDK** — `pip install oci`
- **OCI CLI** — installed and configured (`oci setup config`)
- **Separate API keys per environment** (recommended) or a single key with cross-compartment policies
- **Compartment OCIDs** for each environment (dev, staging, prod)
- Python 3.8+

## Instructions

### Step 1: Configure Multi-Profile ~/.oci/config

The OCI config file supports named profiles. Each profile can point to different tenancies, regions, or use different API keys:

```ini
# ~/.oci/config

[DEFAULT]
user=ocid1.user.oc1..exampleuniqueID
fingerprint=aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99
tenancy=ocid1.tenancy.oc1..exampleuniqueID
region=us-ashburn-1
key_file=~/.oci/oci_api_key.pem

[DEV]
user=ocid1.user.oc1..exampleuniqueID
fingerprint=aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99
tenancy=ocid1.tenancy.oc1..exampleuniqueID
region=us-ashburn-1
key_file=~/.oci/oci_api_key_dev.pem

[STAGING]
user=ocid1.user.oc1..exampleuniqueID
fingerprint=11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00
tenancy=ocid1.tenancy.oc1..exampleuniqueID
region=us-phoenix-1
key_file=~/.oci/oci_api_key_staging.pem

[PROD]
user=ocid1.user.oc1..exampleuniqueID
fingerprint=ff:ee:dd:cc:bb:aa:00:99:88:77:66:55:44:33:22:11
tenancy=ocid1.tenancy.oc1..exampleuniqueID
region=us-ashburn-1
key_file=~/.oci/oci_api_key_prod.pem
```

**Best practice:** Use different API key pairs per environment. If the dev key is compromised, prod is unaffected.

### Step 2: Create an Environment Configuration Module

Centralize compartment OCIDs and profile mappings to prevent OCID confusion:

```python
import oci
import os

# Environment configuration — single source of truth for OCIDs
ENVIRONMENTS = {
    "dev": {
        "profile": "DEV",
        "compartment_id": "ocid1.compartment.oc1..dev_example",
        "region": "us-ashburn-1",
        "allow_destructive": True,
    },
    "staging": {
        "profile": "STAGING",
        "compartment_id": "ocid1.compartment.oc1..staging_example",
        "region": "us-phoenix-1",
        "allow_destructive": True,
    },
    "prod": {
        "profile": "PROD",
        "compartment_id": "ocid1.compartment.oc1..prod_example",
        "region": "us-ashburn-1",
        "allow_destructive": False,  # Safety: block destructive ops
    },
}

def get_oci_config(env_name):
    """Load OCI config for the specified environment.

    Validates the environment name and returns a configured
    OCI config dict ready for client construction.
    """
    if env_name not in ENVIRONMENTS:
        raise ValueError(
            f"Unknown environment: {env_name}. "
            f"Valid: {list(ENVIRONMENTS.keys())}"
        )

    env = ENVIRONMENTS[env_name]
    config = oci.config.from_file("~/.oci/config", profile_name=env["profile"])
    oci.config.validate_config(config)
    return config, env

def get_compartment_id(env_name):
    """Get the compartment OCID for an environment."""
    return ENVIRONMENTS[env_name]["compartment_id"]

def is_destructive_allowed(env_name):
    """Check if destructive operations are allowed in this environment."""
    return ENVIRONMENTS[env_name]["allow_destructive"]
```

### Step 3: Build Safe Environment-Aware Clients

Wrap OCI clients with environment validation to prevent cross-environment mistakes:

```python
import oci
import sys

class OCIEnvironment:
    """Environment-aware OCI client factory with safety guardrails."""

    def __init__(self, env_name):
        self.env_name = env_name
        self.config, self.env = get_oci_config(env_name)
        self.compartment_id = self.env["compartment_id"]

        # Verify we can authenticate
        identity = oci.identity.IdentityClient(self.config)
        user = identity.get_user(self.config["user"]).data
        print(f"[{env_name.upper()}] Authenticated as {user.name} "
              f"in {self.config['region']}")

    def compute(self):
        return oci.core.ComputeClient(self.config)

    def network(self):
        return oci.core.VirtualNetworkClient(self.config)

    def storage(self):
        return oci.object_storage.ObjectStorageClient(self.config)

    def database(self):
        return oci.database.DatabaseClient(self.config)

    def safe_delete(self, operation, resource_name):
        """Execute a delete operation with environment safety checks."""
        if not is_destructive_allowed(self.env_name):
            print(f"BLOCKED: Destructive operation on {resource_name} "
                  f"not allowed in {self.env_name.upper()}")
            print("Set allow_destructive=True in ENVIRONMENTS to override")
            sys.exit(1)

        print(f"WARNING: Deleting {resource_name} in {self.env_name.upper()}")
        return operation()

# Usage
dev = OCIEnvironment("dev")
instances = dev.compute().list_instances(compartment_id=dev.compartment_id).data
print(f"Dev instances: {len(instances)}")

prod = OCIEnvironment("prod")
# prod.safe_delete(...) would be blocked by allow_destructive=False
```

### Step 4: CLI Profile Switching

Use profiles with the OCI CLI to target specific environments:

```bash
# List instances in dev
oci compute instance list --compartment-id ocid1.compartment.oc1..dev_example --profile DEV

# List instances in prod (read-only)
oci compute instance list --compartment-id ocid1.compartment.oc1..prod_example --profile PROD

# Set default profile via environment variable
export OCI_CLI_PROFILE=DEV

# Override per-command
OCI_CLI_PROFILE=PROD oci compute instance list --compartment-id ocid1.compartment.oc1..prod_example
```

**Shell aliases for safety:**

```bash
# Add to ~/.bashrc or ~/.zshrc
alias oci-dev='OCI_CLI_PROFILE=DEV oci'
alias oci-staging='OCI_CLI_PROFILE=STAGING oci'
alias oci-prod='OCI_CLI_PROFILE=PROD oci'

# Usage
oci-dev compute instance list --compartment-id ocid1.compartment.oc1..dev_example
oci-prod compute instance list --compartment-id ocid1.compartment.oc1..prod_example
```

### Step 5: Validate Config Before Operations

Always validate the config file and profile before running automation:

```python
import oci

def validate_all_profiles():
    """Validate all OCI config profiles are properly configured."""
    profiles = ["DEFAULT", "DEV", "STAGING", "PROD"]
    results = {}

    for profile in profiles:
        try:
            config = oci.config.from_file("~/.oci/config", profile_name=profile)
            oci.config.validate_config(config)

            # Test authentication
            identity = oci.identity.IdentityClient(config)
            user = identity.get_user(config["user"]).data
            results[profile] = f"OK — {user.name} in {config['region']}"
        except oci.exceptions.ConfigFileNotFound:
            results[profile] = "FAIL — config file not found"
        except oci.exceptions.ProfileNotFound:
            results[profile] = "FAIL — profile not found in config"
        except oci.exceptions.ServiceError as e:
            results[profile] = f"FAIL — {e.status}: {e.code}"
        except Exception as e:
            results[profile] = f"FAIL — {str(e)}"

    print("OCI Profile Validation:")
    for profile, status in results.items():
        print(f"  [{profile}] {status}")

    return all("OK" in s for s in results.values())

validate_all_profiles()
```

### Step 6: Environment Variables for CI/CD

For CI/CD pipelines where config files are impractical, use environment variables:

```bash
# Set OCI config via environment variables (CI/CD pipelines)
export OCI_CLI_USER="ocid1.user.oc1..exampleuniqueID"
export OCI_CLI_FINGERPRINT="aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99"
export OCI_CLI_TENANCY="ocid1.tenancy.oc1..exampleuniqueID"
export OCI_CLI_REGION="us-ashburn-1"
export OCI_CLI_KEY_FILE="/path/to/key.pem"
# Or use key content directly:
export OCI_CLI_KEY_CONTENT="-----BEGIN RSA PRIVATE KEY-----\n..."
```

```python
import oci

# Python SDK reads from environment when no config file exists
config = oci.config.from_file()  # Falls back to env vars if ~/.oci/config missing

# Or construct config dict directly for CI/CD
config = {
    "user": os.environ["OCI_CLI_USER"],
    "fingerprint": os.environ["OCI_CLI_FINGERPRINT"],
    "tenancy": os.environ["OCI_CLI_TENANCY"],
    "region": os.environ["OCI_CLI_REGION"],
    "key_file": os.environ["OCI_CLI_KEY_FILE"],
}
oci.config.validate_config(config)
```

## Output

Successful completion produces:

- A `~/.oci/config` file with named profiles for each environment (DEV, STAGING, PROD)
- An environment configuration module mapping profiles to compartment OCIDs
- An environment-aware client factory with safety guardrails blocking destructive prod operations
- Shell aliases for safe CLI profile switching
- Validated authentication for all profiles

## Error Handling

| Error | Code | Cause | Solution |
|-------|------|-------|----------|
| ProfileNotFound | — | Wrong profile name in `from_file()` | Check `~/.oci/config` profile names match exactly (case-sensitive) |
| ConfigFileNotFound | — | Missing `~/.oci/config` | Run `oci setup config` or create the file manually |
| NotAuthenticated | 401 | Wrong key for the selected profile | Verify key_file path and fingerprint match the uploaded public key |
| NotAuthorizedOrNotFound | 404 | Profile's user lacks access to target compartment | Add IAM policies for the user/group in the target compartment |
| TooManyRequests | 429 | Rate limited | Back off; see `oraclecloud-rate-limits` |
| InternalError | 500 | OCI service error | Retry after 30s; check https://ocistatus.oraclecloud.com |

**Critical mistake:** Using the DEFAULT profile's compartment OCID with the PROD profile's credentials (or vice versa). The environment config module in Step 2 prevents this by coupling profile names to compartment OCIDs.

## Examples

**Quick profile test from the command line:**

```bash
# Test all profiles in one shot
for profile in DEFAULT DEV STAGING PROD; do
  echo -n "[$profile] "
  oci iam user get --user-id "$(oci iam user list --profile "$profile" --query 'data[0].id' --raw-output 2>/dev/null)" --profile "$profile" --query 'data.name' --raw-output 2>/dev/null || echo "FAILED"
done
```

**Check which profile is active:**

```python
import oci
import os

profile = os.environ.get("OCI_CLI_PROFILE", "DEFAULT")
config = oci.config.from_file("~/.oci/config", profile_name=profile)
print(f"Active profile: {profile}")
print(f"Region: {config['region']}")
print(f"Tenancy: {config['tenancy']}")
```

## Resources

- [OCI Config File](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/sdkconfig.htm) — config file format and profile syntax
- [CLI Environment Variables](https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/clienvironmentvariables.htm) — OCI_CLI_* variables
- [CLI Reference](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/cliconcepts.htm) — command-line interface guide
- [Python SDK Reference](https://docs.oracle.com/en-us/iaas/tools/python/latest/) — config loading and client construction
- [Compartment Management](https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/managingcompartments.htm) — organizing resources by environment

## Next Steps

After environments are configured, see `oraclecloud-enterprise-rbac` for compartment hierarchy design with least-privilege policies, or `oraclecloud-deploy-integration` for CI/CD pipeline integration.

Files in this skill

  • SKILL.md12.3 KB
  • references/one-pager.md1.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.