├── providers.tf ├── compartment.tf ├── variables_user.tf ├── outputs_user.tf ├── groups.tf ├── identity_user.tf ├── outputs.tf ├── variables.tf ├── schema.yaml ├── policies.tf └── README.md /providers.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | required_providers { 4 | oci = { 5 | source = "oracle/oci" 6 | version = ">= 7.13.0" 7 | } 8 | } 9 | } 10 | 11 | provider "oci" { 12 | tenancy_ocid = var.tenancy_ocid 13 | region = var.region 14 | } 15 | -------------------------------------------------------------------------------- /compartment.tf: -------------------------------------------------------------------------------- 1 | # Get the root compartment (tenancy) 2 | data "oci_identity_tenancy" "tenancy" { 3 | tenancy_id = var.tenancy_ocid 4 | } 5 | 6 | # Create the Gen-AI compartment 7 | resource "oci_identity_compartment" "genai_compartment" { 8 | compartment_id = var.tenancy_ocid 9 | description = var.compartment_description 10 | name = var.compartment_name 11 | enable_delete = true 12 | 13 | freeform_tags = var.enable_tagging ? { 14 | Project = var.project_tag 15 | Environment = "development" 16 | Purpose = "genai-experiments" 17 | } : {} 18 | } 19 | -------------------------------------------------------------------------------- /variables_user.tf: -------------------------------------------------------------------------------- 1 | ############################ 2 | # Variables for stack user # 3 | ############################ 4 | 5 | variable "common_freeform_tags" { 6 | description = "Common freeform tags to apply to created resources" 7 | type = map(string) 8 | default = {} 9 | } 10 | 11 | variable "user_name" { 12 | description = "Exact username to create (if null, auto-generated as stackuser-xxxx)" 13 | type = string 14 | default = null 15 | } 16 | 17 | variable "user_description" { 18 | description = "Description for the created user" 19 | type = string 20 | default = "Auto-created by ORM stack" 21 | } 22 | 23 | variable "user_email" { 24 | description = "Optional email for the created user" 25 | type = string 26 | default = null 27 | } 28 | -------------------------------------------------------------------------------- /outputs_user.tf: -------------------------------------------------------------------------------- 1 | ###################### 2 | # User info outputs # 3 | ###################### 4 | 5 | output "new_user_name" { 6 | description = "Username created by the stack" 7 | value = oci_identity_user.stack_user.name 8 | } 9 | 10 | output "new_user_ocid" { 11 | description = "OCID of the created user" 12 | value = oci_identity_user.stack_user.id 13 | } 14 | 15 | output "added_to_group_name" { 16 | description = "Group name the user was added to" 17 | value = oci_identity_group.genai_admin_group[0].name 18 | } 19 | 20 | # One-time Console password returned by OCI; user must change at first login. 21 | output "console_password" { 22 | description = "One-time Console UI password for the created user" 23 | value = oci_identity_ui_password.stack_user_pw.password 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /groups.tf: -------------------------------------------------------------------------------- 1 | # Gen-AI Administrators Group 2 | resource "oci_identity_group" "genai_admin_group" { 3 | count = var.create_groups ? 1 : 0 4 | compartment_id = var.tenancy_ocid 5 | description = "Group for Gen-AI platform administrators with full access to Gen-AI services and resources" 6 | name = var.genai_admin_group_name 7 | 8 | freeform_tags = var.enable_tagging ? { 9 | Project = var.project_tag 10 | Role = "admin" 11 | } : {} 12 | } 13 | 14 | # Gen-AI Users Group 15 | resource "oci_identity_group" "genai_user_group" { 16 | count = var.create_groups ? 1 : 0 17 | compartment_id = var.tenancy_ocid 18 | description = "Group for Gen-AI users with access to use Gen-AI services for text generation experiments" 19 | name = var.genai_user_group_name 20 | 21 | freeform_tags = var.enable_tagging ? { 22 | Project = var.project_tag 23 | Role = "user" 24 | } : {} 25 | } 26 | -------------------------------------------------------------------------------- /identity_user.tf: -------------------------------------------------------------------------------- 1 | ############################################# 2 | # Identity: Create a console user + one-time 3 | # Console password and add to stack group. 4 | ############################################# 5 | 6 | resource "random_string" "user_suffix" { 7 | length = 4 8 | upper = false 9 | lower = true 10 | numeric = true 11 | special = false 12 | } 13 | 14 | locals { 15 | resolved_user_name = coalesce(var.user_name, "stackuser-${random_string.user_suffix.result}") 16 | } 17 | 18 | resource "oci_identity_user" "stack_user" { 19 | compartment_id = var.tenancy_ocid 20 | name = local.resolved_user_name 21 | description = var.user_description 22 | email = var.user_email 23 | freeform_tags = merge( 24 | var.common_freeform_tags, 25 | { "created-by" = "orm-stack" } 26 | ) 27 | } 28 | 29 | # Create a one-time Console password (OCI generates and returns it). 30 | resource "oci_identity_ui_password" "stack_user_pw" { 31 | user_id = oci_identity_user.stack_user.id 32 | } 33 | 34 | # Add the user to the stack-created group (counted resource -> [0]). 35 | resource "oci_identity_user_group_membership" "membership" { 36 | user_id = oci_identity_user.stack_user.id 37 | group_id = oci_identity_group.genai_admin_group[0].id 38 | } 39 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "compartment_ocid" { 2 | description = "OCID of the created compartment" 3 | value = oci_identity_compartment.genai_compartment.id 4 | } 5 | 6 | output "compartment_name" { 7 | description = "Name of the created compartment" 8 | value = oci_identity_compartment.genai_compartment.name 9 | } 10 | 11 | output "genai_admin_group_ocid" { 12 | description = "OCID of the Gen-AI admin group" 13 | value = var.create_groups ? oci_identity_group.genai_admin_group[0].id : null 14 | } 15 | 16 | output "genai_user_group_ocid" { 17 | description = "OCID of the Gen-AI user group" 18 | value = var.create_groups ? oci_identity_group.genai_user_group[0].id : null 19 | } 20 | 21 | output "genai_admin_policy_ocid" { 22 | description = "OCID of the Gen-AI admin policy" 23 | value = var.create_groups ? oci_identity_policy.genai_admin_policy[0].id : null 24 | } 25 | 26 | output "genai_user_policy_ocid" { 27 | description = "OCID of the Gen-AI user policy" 28 | value = var.create_groups ? oci_identity_policy.genai_user_policy[0].id : null 29 | } 30 | 31 | output "deployment_summary" { 32 | description = "Summary of deployed resources" 33 | value = { 34 | compartment_name = oci_identity_compartment.genai_compartment.name 35 | compartment_ocid = oci_identity_compartment.genai_compartment.id 36 | groups_created = var.create_groups 37 | admin_group = var.create_groups ? var.genai_admin_group_name : "not created" 38 | user_group = var.create_groups ? var.genai_user_group_name : "not created" 39 | region = var.region 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "tenancy_ocid" { 2 | description = "The OCID of the tenancy" 3 | type = string 4 | } 5 | 6 | variable "region" { 7 | description = "The region where resources will be created" 8 | type = string 9 | } 10 | 11 | variable "compartment_name" { 12 | description = "Name for the Gen-AI compartment" 13 | type = string 14 | default = "genai-experiments" 15 | 16 | validation { 17 | condition = can(regex("^[a-zA-Z][a-zA-Z0-9_-]*$", var.compartment_name)) 18 | error_message = "Compartment name must start with a letter and contain only letters, numbers, underscores, and hyphens." 19 | } 20 | } 21 | 22 | variable "compartment_description" { 23 | description = "Description for the Gen-AI compartment" 24 | type = string 25 | default = "Compartment for Gen-AI text generation experiments and resources" 26 | } 27 | 28 | variable "create_groups" { 29 | description = "Whether to create IAM groups for Gen-AI access" 30 | type = bool 31 | default = true 32 | } 33 | 34 | variable "genai_admin_group_name" { 35 | description = "Name for the Gen-AI administrators group" 36 | type = string 37 | default = "genai-admins" 38 | } 39 | 40 | variable "genai_user_group_name" { 41 | description = "Name for the Gen-AI users group" 42 | type = string 43 | default = "genai-users" 44 | } 45 | 46 | variable "enable_tagging" { 47 | description = "Whether to apply tags to created resources" 48 | type = bool 49 | default = true 50 | } 51 | 52 | variable "project_tag" { 53 | description = "Project tag to apply to resources" 54 | type = string 55 | default = "genai-platform" 56 | } 57 | -------------------------------------------------------------------------------- /schema.yaml: -------------------------------------------------------------------------------- 1 | title: "Gen-AI Platform Setup" 2 | description: "Creates compartments, groups, and policies for Gen-AI text generation experiments" 3 | schemaVersion: 1.1.0 4 | version: "1.0.0" 5 | locale: "en" 6 | 7 | variableGroups: 8 | - title: "General Configuration" 9 | visible: true 10 | variables: 11 | - tenancy_ocid 12 | - region 13 | - compartment_name 14 | - compartment_description 15 | 16 | - title: "Groups Configuration" 17 | visible: true 18 | variables: 19 | - create_groups 20 | - genai_admin_group_name 21 | - genai_user_group_name 22 | 23 | - title: "Tags Configuration" 24 | visible: true 25 | variables: 26 | - enable_tagging 27 | - project_tag 28 | 29 | variables: 30 | tenancy_ocid: 31 | type: string 32 | title: "Tenancy OCID" 33 | description: "The OCID of your tenancy" 34 | required: true 35 | 36 | region: 37 | type: oci:identity:region:name 38 | title: "Region" 39 | description: "The region where resources will be created" 40 | required: true 41 | 42 | compartment_name: 43 | type: string 44 | title: "Compartment Name" 45 | description: "Name for the Gen-AI compartment" 46 | required: true 47 | default: "genai-experiments" 48 | pattern: "^[a-zA-Z][a-zA-Z0-9_-]*$" 49 | 50 | compartment_description: 51 | type: string 52 | title: "Compartment Description" 53 | description: "Description for the Gen-AI compartment" 54 | required: false 55 | default: "Compartment for Gen-AI text generation experiments and resources" 56 | 57 | create_groups: 58 | type: boolean 59 | title: "Create IAM Groups" 60 | description: "Whether to create IAM groups for Gen-AI access" 61 | required: false 62 | default: true 63 | 64 | genai_admin_group_name: 65 | type: string 66 | title: "Gen-AI Admin Group Name" 67 | description: "Name for the Gen-AI administrators group" 68 | required: false 69 | default: "genai-admins" 70 | visible: ${create_groups} 71 | 72 | genai_user_group_name: 73 | type: string 74 | title: "Gen-AI Users Group Name" 75 | description: "Name for the Gen-AI users group" 76 | required: false 77 | default: "genai-users" 78 | visible: ${create_groups} 79 | 80 | enable_tagging: 81 | type: boolean 82 | title: "Enable Resource Tagging" 83 | description: "Whether to apply tags to created resources" 84 | required: false 85 | default: true 86 | 87 | project_tag: 88 | type: string 89 | title: "Project Tag" 90 | description: "Project tag to apply to resources" 91 | required: false 92 | default: "genai-platform" 93 | visible: ${enable_tagging} 94 | 95 | outputs: 96 | compartment_ocid: 97 | type: copyableString 98 | title: "Compartment OCID" 99 | description: "OCID of the created compartment" 100 | 101 | genai_admin_group_ocid: 102 | type: copyableString 103 | title: "Gen-AI Admin Group OCID" 104 | description: "OCID of the Gen-AI admin group" 105 | 106 | genai_user_group_ocid: 107 | type: copyableString 108 | title: "Gen-AI User Group OCID" 109 | description: "OCID of the Gen-AI user group" 110 | -------------------------------------------------------------------------------- /policies.tf: -------------------------------------------------------------------------------- 1 | # Policy for Gen-AI Administrators 2 | resource "oci_identity_policy" "genai_admin_policy" { 3 | count = var.create_groups ? 1 : 0 4 | compartment_id = var.tenancy_ocid 5 | description = "Policy granting Gen-AI administrators full access to manage Gen-AI services and related resources" 6 | name = "${var.compartment_name}-admin-policy" 7 | 8 | statements = [ 9 | "Allow group ${var.genai_admin_group_name} to manage generative-ai-family in compartment ${var.compartment_name}", 10 | "Allow group ${var.genai_admin_group_name} to manage ai-service-language-family in compartment ${var.compartment_name}", 11 | "Allow group ${var.genai_admin_group_name} to manage ai-service-document-family in compartment ${var.compartment_name}", 12 | "Allow group ${var.genai_admin_group_name} to manage ai-service-speech-family in compartment ${var.compartment_name}", 13 | "Allow group ${var.genai_admin_group_name} to manage ai-service-vision-family in compartment ${var.compartment_name}", 14 | "Allow group ${var.genai_admin_group_name} to manage data-science-family in compartment ${var.compartment_name}", 15 | "Allow group ${var.genai_admin_group_name} to manage object-family in compartment ${var.compartment_name}", 16 | "Allow group ${var.genai_admin_group_name} to manage logging-family in compartment ${var.compartment_name}", 17 | "Allow group ${var.genai_admin_group_name} to manage metrics in compartment ${var.compartment_name}" 18 | , "Allow group ${var.genai_admin_group_name} to manage alarms in compartment ${var.compartment_name}", 19 | "Allow group ${var.genai_admin_group_name} to use cloud-shell in tenancy", 20 | "Allow group ${var.genai_admin_group_name} to inspect compartments in tenancy" 21 | ] 22 | 23 | depends_on = [ 24 | oci_identity_compartment.genai_compartment, 25 | oci_identity_group.genai_admin_group 26 | ] 27 | 28 | freeform_tags = var.enable_tagging ? { 29 | Project = var.project_tag 30 | Type = "admin-policy" 31 | } : {} 32 | } 33 | 34 | # Policy for Gen-AI Users 35 | resource "oci_identity_policy" "genai_user_policy" { 36 | count = var.create_groups ? 1 : 0 37 | compartment_id = var.tenancy_ocid 38 | description = "Policy granting Gen-AI users access to use Gen-AI services for text generation experiments" 39 | name = "${var.compartment_name}-user-policy" 40 | 41 | statements = [ 42 | "Allow group ${var.genai_user_group_name} to use generative-ai-family in compartment ${var.compartment_name}", 43 | "Allow group ${var.genai_user_group_name} to use ai-service-language-family in compartment ${var.compartment_name}", 44 | "Allow group ${var.genai_user_group_name} to read ai-service-document-family in compartment ${var.compartment_name}", 45 | "Allow group ${var.genai_user_group_name} to read buckets in compartment ${var.compartment_name}", 46 | "Allow group ${var.genai_user_group_name} to read objects in compartment ${var.compartment_name}", 47 | "Allow group ${var.genai_user_group_name} to manage objects in compartment ${var.compartment_name} where target.bucket.name=/genai-.*/", 48 | "Allow group ${var.genai_user_group_name} to use data-science-family in compartment ${var.compartment_name}", 49 | "Allow group ${var.genai_user_group_name} to read logging-family in compartment ${var.compartment_name}", 50 | "Allow group ${var.genai_user_group_name} to read metrics in compartment ${var.compartment_name}", 51 | "Allow group ${var.genai_user_group_name} to use cloud-shell in tenancy", 52 | "Allow group ${var.genai_user_group_name} to inspect compartments in tenancy" 53 | ] 54 | 55 | depends_on = [ 56 | oci_identity_compartment.genai_compartment, 57 | oci_identity_group.genai_user_group 58 | ] 59 | 60 | freeform_tags = var.enable_tagging ? { 61 | Project = var.project_tag 62 | Type = "user-policy" 63 | } : {} 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Text Generation Stack (OCI Resource Manager) – Auto User & Groups 2 | 3 | A one-click **OCI Resource Manager** (ORM) stack that prepares identity and guardrails for Gen‑AI / Text Generation projects: 4 | - (Optional) **Project Compartment** 5 | - **Two IAM Groups** (e.g., GenAI Admins & GenAI Users) 6 | - **OCI IAM User** (auto‑created) with optional email + description 7 | - **Policies** granting the groups/user access as defined in the stack 8 | 9 | > ✅ Terraform files are already structured for ORM. Commit them to a public GitHub repo and use the **Deploy to Oracle Cloud** button below. 10 | 11 | --- 12 | 13 | ## Deploy with One Click 14 | 15 | [![Deploy to Oracle Cloud](https://oci-resourcemanager-plugin.plugins.oci.oraclecloud.com/latest/deploy-to-oracle-cloud.svg)](https://cloud.oracle.com/resourcemanager/stacks/create?zipUrl=https://github.com/ou-developers/GenAI-TextVisual-Sandbox-Stack/archive/refs/heads/main.zip) 16 | 17 | **Alternative (no tag yet):** 18 | ``` 19 | https://cloud.oracle.com/resourcemanager/stacks/create?zipUrl=https://github.com/ou-developers/GenAI-TextVisual-Sandbox-Stack/archive/refs/heads/main.zip 20 | ``` 21 | 22 | > Tip: Open your `zipUrl` in an **incognito** window—the link must download a `.zip` with no login prompt. Make sure your `.tf` files are committed at the **repo root** of that tag/branch. 23 | 24 | --- 25 | 26 | ## Prerequisites 27 | 28 | - OCI tenancy + permissions to create **Resource Manager** stacks and Identity resources (Compartment, Groups, User, Policies). 29 | - Your **Tenancy OCID** and **Deployment region** (you’ll choose region in Console). 30 | - (Optional) Email address for the new user. 31 | - (Optional) If you need custom tags, prepare your tag keys/values. 32 | 33 | --- 34 | 35 | ## Inputs (common variables) 36 | 37 | > See `variables.tf` and `variables_user.tf` for full list. Typical variables include: 38 | 39 | - `tenancy_ocid` *(string, required)* – Your tenancy OCID. 40 | - `region` *(string, required)* – Target region (e.g., `ap-mumbai-1`). 41 | - **Compartment options** 42 | - `create_compartment` *(bool, default: true)* 43 | - `project_compartment_name` *(string)* 44 | - `project_compartment_description` *(string)* 45 | - **Groups** 46 | - `create_groups` *(bool, default: true)* 47 | - `genai_admin_group_name` *(string, default suggestion: `GenAI-Admins`)* 48 | - `genai_user_group_name` *(string, default suggestion: `GenAI-Users`)* 49 | - **User (auto‑create)** 50 | - `user_name` *(string, required)* – Login/username for the new IAM user. 51 | - `user_email` *(string, optional)* – For notifications / identity email. 52 | - `user_description` *(string, default: "Created by ORM stack")* 53 | - **Tagging (optional)** 54 | - `enable_tagging` *(bool)*, `project_tag` *(string)*, `common_freeform_tags` *(map(string))* 55 | 56 | > Names and booleans above match what this stack expects. Adjust defaults to your policy/namespace conventions. 57 | 58 | --- 59 | 60 | ## Optional: Prefill values in the button 61 | 62 | Append `zipUrlVariables=` with **URL‑encoded JSON** (leave `region` out if you prefer choosing it in Console). Example: 63 | 64 | **JSON:** 65 | ```json 66 | { 67 | "create_compartment": true, 68 | "project_compartment_name": "genai-textgen", 69 | "create_groups": true, 70 | "genai_admin_group_name": "GenAI-Admins", 71 | "genai_user_group_name": "GenAI-Users", 72 | "user_name": "genai.stack.user", 73 | "user_email": "user@example.com", 74 | "user_description": "Created by Quick-Create" 75 | } 76 | ``` 77 | 78 | **URL‑encoded to append:** 79 | ``` 80 | &zipUrlVariables=%7B%22create_compartment%22%3Atrue%2C%22project_compartment_name%22%3A%22genai-textgen%22%2C%22create_groups%22%3Atrue%2C%22genai_admin_group_name%22%3A%22GenAI-Admins%22%2C%22genai_user_group_name%22%3A%22GenAI-Users%22%2C%22user_name%22%3A%22genai.stack.user%22%2C%22user_email%22%3A%22user%40example.com%22%2C%22user_description%22%3A%22Created%20by%20Quick-Create%22%7D 81 | ``` 82 | 83 | --- 84 | 85 | ## What this stack creates 86 | 87 | - **Compartment** (when `create_compartment = true`). 88 | - **Groups** for admins and users (when `create_groups = true`). Membership of the new user can be added per policy or post‑create. 89 | - **Policies** granting appropriate permissions to the groups for your project scope. 90 | - **IAM User** created with the provided name/email/description. Retrieve credentials out‑of‑band as per org policy. 91 | 92 | > Exact resources are defined in: `compartment.tf`, `groups.tf`, `policies.tf`, `identity_user.tf`, and outputs in `outputs.tf`, `outputs_user.tf`. 93 | 94 | --- 95 | 96 | ## Outputs 97 | 98 | Open the **Outputs** tab after Apply. Common outputs include: 99 | - Compartment OCID (if created) 100 | - Group names/OCIDs (admins/users) 101 | - IAM User name/OCID (if created) 102 | 103 | --- 104 | 105 | ## Post‑Deploy: Verify 106 | 107 | - **Identity → Users**: new user exists and email/description are set. 108 | - **Identity → Groups**: admin/user groups exist; add members as needed. 109 | - **Identity → Policies**: policies compiled/applied without errors. 110 | 111 | --- 112 | 113 | ## Clean Up 114 | 115 | 1. In ORM → your stack → **Jobs**, run **Destroy**. 116 | 2. Delete the stack (and any manual leftovers if you created resources outside the stack). 117 | 118 | --- 119 | 120 | ## How to publish this repo (quick Git steps) 121 | 122 | ```bash 123 | # inside the folder with these .tf files at top level 124 | git init 125 | git add . 126 | git commit -m "Initial: Text Generation identity stack (auto user & groups)" 127 | git branch -M main 128 | git remote add origin https://github.com//.git 129 | git push -u origin main 130 | 131 | # make a stable tag for the Deploy button 132 | git tag -a v1.0.0 -m "Initial release" 133 | git push origin v1.0.0 134 | ``` 135 | Now your Deploy button (above) works against that tag archive. 136 | --------------------------------------------------------------------------------