├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs └── diagrams │ ├── versions.iuml │ └── versions.svg ├── examples ├── README.md ├── hierarchical_compartment_config.yaml ├── hierarchical_compartments.tf ├── main.tf ├── outputs.tf └── terraform.tfvars.sample └── modules ├── iam-compartment ├── README.md ├── main.tf ├── outputs.tf ├── variables.tf └── versions.tf ├── iam-dynamic-group ├── README.md ├── main.tf ├── outputs.tf ├── variables.tf └── versions.tf ├── iam-group ├── README.md ├── main.tf ├── outputs.tf ├── variables.tf └── versions.tf ├── iam-hierarchical-compartment ├── README.md ├── main.tf ├── outputs.tf ├── variables.tf └── versions.tf └── iam-user ├── README.md ├── main.tf ├── outputs.tf ├── variables.tf └── versions.tf /.gitattributes: -------------------------------------------------------------------------------- 1 | *.txt text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=4 2 | *.md text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=4 3 | *.tf text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=4 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | terraform.tfvars 2 | .terraform 3 | *.tfstate 4 | *.tfstate.backup 5 | *.lock 6 | 7 | tests 8 | 9 | .DS_Store 10 | .vscode 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # Changelog 3 | 4 | All notable changes to this project will be documented in this file. 5 | 6 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and the versioning follows the [Semantic Versioning 2.0.0](https://semver.org/) specification. 7 | 8 | Given a version number MAJOR.MINOR.PATCH: 9 | 10 | - MAJOR version when making incompatible API changes, 11 | - MINOR version when adding functionality in a backwards compatible manner, 12 | - PATCH version when making backwards compatible bug fixes. 13 | 14 | ## [2.0.2] - 2025-05-27 15 | 16 | ### Added 17 | 18 | #### New features 19 | 20 | - iam-hierarchical-compartment 21 | 22 | ## [2.0.1] - 2021-02-09 23 | 24 | ### Fixed 25 | 26 | - missing description for outputs 27 | - Remove uncorrect module version from examples (Issue #18) 28 | - typo in examples/main.tf for iam_dynamic_group module source path (Issue #19) 29 | - explanation of `enable_delete` argument behaviour in modules/iam-compartment documentation (Issue #20) 30 | 31 | ### Changed 32 | 33 | - no more version pinning in examples to keep documentation current, but add a note on how to do it for production code. 34 | 35 | ## [2.0.0] - 2021-01-27 36 | 37 | ### Added 38 | 39 | #### New features 40 | 41 | - delete a compartment 42 | - create a sub-compartment 43 | - create a list of oci users 44 | - set email of oci user 45 | 46 | #### Documentation 47 | 48 | - CHANGELOG following [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) format 49 | - CONTRIBUTING guide 50 | - prerequisites section with the required Terraform and Terraform Provider versions 51 | - clarify provider configuration requirements for OCI IAM resources (you must your home region) 52 | - README for /examples 53 | - examples on how to use the new features of this module 54 | 55 | ### Changed 56 | 57 | #### Resources 58 | 59 | - `count` tests with true/false for boolean variables, 60 | - `count` tests with null or variable length for arrays. 61 | 62 | #### modules/* 63 | 64 | - terraform and OCI terraform provider version pinning block : Terraform 0.12 and OCI Provider 3.27 or greater 65 | - new outputs for each sub-modules 66 | - typed variables 67 | - variables default value is `null` if there is no better advisable value 68 | 69 | #### modules/iam-compartment 70 | 71 | - compartment_name and compartment_description are now mandatory (default value is null), 72 | - compartment_id is now optional: if the parent compartment ID is not specified, the compartment is created at the root level of the tenancy 73 | 74 | #### modules/iam-user 75 | 76 | - name and description are now mandatory (default value is null) 77 | 78 | ### Fixed 79 | 80 | - Issues: #11 #12 #16 81 | - no more deprecated interpolation syntax in modules and examples 82 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | Oracle welcomes contributions to this repository from anyone. 4 | 5 | If you want to submit a pull request to fix a bug or enhance an existing feature, please first open an issue and link to that issue when you submit your pull request. 6 | 7 | If you have any questions about a possible submission, feel free to open an issue too. 8 | 9 | ## Contributing to the terraform-oci-iam repository 10 | 11 | Pull requests can be made under The Oracle Contributor Agreement(OCA). 12 | 13 | For pull requests to be accepted, the bottom of your commit message must have the following line using your name and e-mail address as it appears in the OCA Signatories list. 14 | 15 | `Signed-off-by: Your Name ` 16 | 17 | This can be automatically added to pull requests by committing with: 18 | 19 | `git commit --signoff` 20 | 21 | or by turning on the "Always Sign Off" flag in your IDE's preferences. 22 | 23 | Only pull requests from committers that can be verified as having signed the OCA can be accepted. 24 | 25 | ## Pull request process 26 | 27 | 1. Fork this repository 28 | 29 | 1. Create a branch in your own fork to implement the changes. We recommend using the issue number as part of your branch name, e.g.: `1234-fixes` 30 | 31 | 1. Ensure that any documentation is updated with the changes that are required by your fix 32 | 33 | 1. Update README.md when necessary 34 | 35 | 1. Ensure that any samples are updated if the base image has been changed 36 | 37 | 1. Update CHANGELOG.md - add information about the changes that are done in this pull request, increment the version 38 | 39 | 1. Tag your branch with the new version 40 | 41 | 1. Submit the pull request. **Do not leave the pull request description blank**. Explain exactly what your changes are meant to do and provide simple steps on how to validate your changes. Ensure that you reference the issue you created as well adding `#1234` to the description. We will assign the pull request to 2-3 people for review before it is merged. 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | 3 | This software is dual-licensed to you under the Universal Permissive License (UPL) or Apache License 2.0. See below for license terms. You may choose either license. 4 | ____________________________ 5 | The Universal Permissive License (UPL), Version 1.0 6 | 7 | Subject to the condition set forth below, permission is hereby granted to any 8 | person obtaining a copy of this software, associated documentation and/or data 9 | (collectively the "Software"), free of charge and under any and all copyright 10 | rights in the Software, and any and all patent rights owned or freely 11 | licensable by each licensor hereunder covering either (i) the unmodified 12 | Software as contributed to or provided by such licensor, or (ii) the Larger 13 | Works (as defined below), to deal in both 14 | 15 | (a) the Software, and 16 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 17 | one is included with the Software (each a "Larger Work" to which the Software 18 | is contributed by such licensors), 19 | 20 | without restriction, including without limitation the rights to copy, create 21 | derivative works of, display, perform, and distribute the Software and make, 22 | use, sell, offer for sale, import, export, have made, and have sold the 23 | Software and the Larger Work(s), and to sublicense the foregoing rights on 24 | either these or other terms. 25 | 26 | This license is subject to the following condition: 27 | The above copyright notice and either this complete permission notice or at 28 | a minimum a reference to the UPL must be included in all copies or 29 | substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | 39 | ____________________________ 40 | The Apache Software License, Version 2.0 41 | // Copyright (c) 2018, 2021, Oracle and/or its affiliates. 42 | 43 | Licensed under the Apache License, Version 2.0 (the "License"); You may not use this product except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. A copy of the license is also reproduced below. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 44 | 45 | Apache License 46 | 47 | Version 2.0, January 2004 48 | 49 | http://www.apache.org/licenses/ 50 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 51 | 1. Definitions. 52 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 53 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 54 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 55 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 56 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 57 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 58 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 59 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 60 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 61 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 62 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 63 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 64 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 65 | You must give any other recipients of the Work or Derivative Works a copy of this License; and 66 | You must cause any modified files to carry prominent notices stating that You changed the files; and 67 | You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 68 | If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 69 | 70 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 71 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 72 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 73 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 74 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 75 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 76 | END OF TERMS AND CONDITIONS 77 | 78 | APPENDIX: How to apply the Apache License to your work. 79 | 80 | To apply the Apache License to your work, attach the following 81 | boilerplate notice, with the fields enclosed by brackets "[]" 82 | replaced with your own identifying information. (Don't include 83 | the brackets!) The text should be enclosed in the appropriate 84 | comment syntax for the file format. We also recommend that a 85 | file or class name and description of purpose be included on the 86 | same "printed page" as the copyright notice for easier 87 | identification within third-party archives. 88 | 89 | Copyright [yyyy] [name of copyright owner] 90 | 91 | Licensed under the Apache License, Version 2.0 (the "License"); 92 | you may not use this file except in compliance with the License. 93 | You may obtain a copy of the License at 94 | 95 | http://www.apache.org/licenses/LICENSE-2.0 96 | 97 | Unless required by applicable law or agreed to in writing, software 98 | distributed under the License is distributed on an "AS IS" BASIS, 99 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 100 | See the License for the specific language governing permissions and 101 | limitations under the License. 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Oracle Cloud Infrastructure Terraform Modules for Identity and Access Management (oci-iam) v2 2 | 3 | This module contains a collection of submodules that simplify the management of Identity and Access Management (IAM) resources such as compartments, users, groups, and dynamic groups for Oracle Cloud Infrastructure. For more information about IAM, see [Overview of IAM](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/overview.htm). 4 | 5 | Note: the root folder of this module contains no Terraform code: it groups together the related submodules. 6 | 7 | The file and directory layout follows the [Terraform Standard Module Structure](https://www.terraform.io/docs/modules/structure.html): 8 | 9 | * [modules](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/modules) folder contains several standalone, reusable, submodules for creating IAM resources in Oracle Cloud Infrastructure, 10 | * [examples](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/examples) folder contains fully-functional examples that you can copy and paste "as is" to have a first look at the submodules capabilities. 11 | 12 | ## Maintainers 13 | 14 | This module is maintained by Oracle. 15 | 16 | ## What's new in v2? 17 | 18 | ### iam-compartment 19 | 20 | * Add support for nested Compartments, 21 | * Add support for Compartment deletion, 22 | * DEPRECATED: `compartment_create` argument, which creates a data source instead of a resource when set to `false`. This argument will be removed in the next major release. 23 | * DEPRECATED: `tenancy_ocid`. The preferred argument is now `compartment_id`, as it can be used to create compartments at the tenancy root level and as a nested compartment. 24 | 25 | ### iam-user 26 | 27 | * Add for creating a list of users from a single module, 28 | * Add support for defining user email. 29 | 30 | ### iam-group 31 | 32 | * DEPRECATED: `group_create` argument, which creates a data source instead of a resource when set to `false`. This argument will be removed in the next major release. 33 | 34 | ### iam-dynamic-group 35 | 36 | * DEPRECATED: `dynamic_group_create` argument, which creates a data source instead of a resource when set to `false`. This argument will be removed in the next major release. 37 | 38 | ## Requirements 39 | 40 | * Terraform 0.12.x 41 | * OCI Terraform Provider 3.27 or greater 42 | 43 | This modules and its submodules, in version 2, are optimized for Terraform v0.12: 44 | 45 | * They will not run at all, or not as intended with a Terraform version below v0.12.0, 46 | * They are not tested with Terraform versions above v0.12 and may produce unexpected behaviors. 47 | 48 | The first OCI Terraform provider version to work with Terraform v0.12 is provider.oci v3.27. 49 | 50 | * you must use OCI Terraform Provider v3.27 or above, 51 | * this module and its submodules are not extensively tested with OCI Terraform Provider versions 4 and above, 52 | * It may work and give richer informations for some resources, but also produce unexpected behaviors under certain circumstances. 53 | 54 | The diagram below summarizes the required components and their respective versions to use this module. 55 | 56 | ![versions](https://github.com/oracle-terraform-modules/terraform-oci-iam/blob/master/docs/diagrams/versions.svg?raw=true&sanitize=true) 57 | 58 | To enforce versions compatibility of both Terraform and the OCI provider, your root configuration should ideally include this block in main.tf for version pinning: 59 | 60 | ```HCL 61 | terraform { 62 | required_version = ">= 0.12, < 0.13" 63 | required_providers { 64 | oci = { 65 | version = ">= 3.27, < 4.0" 66 | } 67 | } 68 | } 69 | ``` 70 | 71 | See the [Oracle Cloud Infrastructure Terraform Provider docs](https://registry.terraform.io/providers/hashicorp/oci/latest/docs) for detailed information about setting up and using the Oracle Cloud Infrastructure Terraform Provider. 72 | 73 | ## How to use the submodules 74 | 75 | You should always pin the version of this module in your configuration: add the `version` argument of the module block in your root configuration. 76 | 77 | * To use v2 of this module for Terraform 0.12: 78 | 79 | ```HCL 80 | module "iam" { 81 | source = "oracle-terraform-modules/iam/oci" 82 | version = "2.0.0" 83 | } 84 | ``` 85 | 86 | * to use v1 of this module for Terraform 0.11 compatibility: 87 | 88 | ```HCL 89 | module "iam" { 90 | source = "oracle-terraform-modules/iam/oci" 91 | version = "1.0.3" 92 | } 93 | ``` 94 | 95 | Note: 96 | 97 | - *adjust the minor and patch version of the module according to your needs. If version is omitted, the latest available version on the registry will be used.* 98 | - *When using the oci-iam modules, or more generally when manipulating iam resources, **be sure to configure your oci provider to use the tenancy's home region**, as IAM resources can only be managed from the home region.* 99 | - To combine this template with non-iam resources provisioned in a region different from your *home region*, you will need to use [provider aliases](https://www.terraform.io/docs/configuration/providers.html#alias-multiple-provider-configurations). 100 | 101 | The available submodules are listed below with example block codes. For fully-functional examples, please see [examples](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/examples). 102 | 103 | ### Declaring OCI Compartments with iam-compartment 104 | 105 | See a basic example below and [the iam-compartment readme](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/modules/iam-compartment) for details. 106 | 107 | * To create a compartment at the root level of the tenancy, insert this block in your root configuration: 108 | 109 | ```HCL 110 | module "iam_compartment" { 111 | source = "oracle-terraform-modules/iam/oci//modules/iam-compartment" 112 | tenancy_ocid = var.tenancy_ocid 113 | compartment_id = var.tenancy_ocid # define the parent compartment. Creation at tenancy root if omitted 114 | compartment_name = "tf_example_compartment" 115 | compartment_description = "compartment at root level created - terraformed" 116 | compartment_create = true # if false, a data source with a matching name is created instead 117 | enable_delete = true # if false, on `terraform destroy`, compartment is deleted from the terraform state but not from oci 118 | } 119 | ``` 120 | 121 | * To create a sub-compartment, with the previously created compartment as parent, insert this block in your root configuration: 122 | 123 | ```HCL 124 | module "iam_subcompartment" { 125 | source = "oracle-terraform-modules/iam/oci//modules/iam-compartment" 126 | tenancy_ocid = var.tenancy_ocid 127 | compartment_id = module.iam_compartment.compartment_id # define the parent compartment. Here we make reference to the previous module's output 128 | compartment_name = "tf_example_subcompartment" 129 | compartment_description = "subcompartment created below tf_example_compartment - terraformed" 130 | compartment_create = true # if false, a data source with a matching name is created instead 131 | enable_delete = true # if false, on `terraform destroy`, compartment is deleted from the terraform state but not from oci 132 | } 133 | ``` 134 | 135 | ### Declaring a list of OCI Users with iam-user 136 | 137 | See a basic example below and [the iam-user readme](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/modules/iam-user) for details. 138 | 139 | * To create a list of users, insert this block in your root configuration: 140 | 141 | ```HCL 142 | module "iam_users" { 143 | source = "oracle-terraform-modules/iam/oci//modules/iam-user" 144 | version = "2.0.0" 145 | tenancy_ocid = var.tenancy_ocid # required 146 | users = [ # a list of users 147 | { # user1 148 | name = "tf_example_user1@example.com" # required 149 | description = "user1 - terraformed" # required 150 | email = null # set to null if you don't want to provide an email 151 | }, 152 | { # user2 153 | name = "tf_example_user2@example.com" 154 | description = "user2 - terraformed" 155 | email = "tf_example_user2@example.com" 156 | }, 157 | { # user3 158 | name = "tf_example_user3@example.com" 159 | description = "user3 - terraformed" 160 | email = "tf_example_user3@example.com" 161 | },# add more users below as needed 162 | ] 163 | } 164 | ``` 165 | 166 | ### Declaring OCI Groups with iam-group 167 | 168 | See a basic example below and [the iam-group readme](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/modules/iam-group) for details. 169 | 170 | * To create a group, add previously declared users as members and create an IAM policy in the previously declared compartment, insert this block in your root configuration: 171 | 172 | ```HCL 173 | module "iam_group" { 174 | source = "oracle-terraform-modules/iam/oci//modules/iam-group" 175 | version = "2.0.0" 176 | tenancy_ocid = var.tenancy_ocid # required 177 | group_name = "tf_example_group" # required 178 | group_description = "an example group - terraformed" # required 179 | user_ids = [element(module.iam_users.user_id,0),element(module.iam_users.user_id,1),element(module.iam_users.user_id,2)] # a list of user ocids 180 | policy_name = "tf-example-policy" # optional 181 | policy_compartment_id = module.iam_compartment.compartment_id # optional 182 | policy_description = "policy created by terraform" # optional 183 | policy_statements = [ # optional 184 | "Allow group ${module.iam_group.group_name} to read instances in compartment tf_example_compartment", 185 | "Allow group ${module.iam_group.group_name} to inspect instances in compartment tf_example_compartment", 186 | ] 187 | } 188 | ``` 189 | 190 | ### Declaring OCI Dynamic Groups with iam-dynamic-group 191 | 192 | See a basic example below and [the iam-dynamic-group readme](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/modules/iam-dynamic-group) for details. 193 | 194 | * To create a dynamic group with a matching rule, and create an IAM policy in the previously declared compartment, insert this block in your root configuration: 195 | 196 | ```HCL 197 | module "iam_dynamic_group" { 198 | source = "oracle-terraform-modules/iam/oci//modules/iam-dynamic-group" 199 | tenancy_ocid = var.tenancy_ocid 200 | dynamic_group_name = "tf_example_dynamic_group" 201 | dynamic_group_description = "dynamic group created by terraform" 202 | matching_rule = "instance.compartment.id = '${module.iam_compartment.compartment_id}'" 203 | policy_compartment_id = module.iam_compartment.compartment_id 204 | policy_name = "tf-example-dynamic-policy" 205 | policy_description = "dynamic policy created by terraform" 206 | policy_statements = [ 207 | "Allow dynamic-group ${module.iam_dynamic_group.dynamic_group_name} to read instances in compartment tf_example_compartment" 208 | ] 209 | } 210 | ``` 211 | 212 | ## Contributing 213 | 214 | This project is open source. Oracle appreciates any contributions that are made by the open source community. 215 | 216 | Learn how to [contribute](https://github.com/oracle-terraform-modules/terraform-oci-iam/blob/master/CONTRIBUTING.md). 217 | 218 | ## License 219 | 220 | Copyright (c) 2018, 2021, Oracle and/or its affiliates. 221 | 222 | Licensed under the Universal Permissive License 1.0 or Apache License 2.0. 223 | 224 | See [LICENSE](https://github.com/oracle-terraform-modules/terraform-oci-iam/blob/master/LICENSE) for more details. 225 | -------------------------------------------------------------------------------- /docs/diagrams/versions.iuml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | skinparam object { 4 | FontColor #312D2A 5 | BorderColor #312D2A 6 | ArrowColor 312D2A 7 | FontName "Oracle Sans" 8 | FontSize 15 9 | } 10 | 11 | skinparam objectAttribute { 12 | FontColor #312D2A 13 | BorderColor #312D2A 14 | FontName "menlo" 15 | FontSize 13 16 | } 17 | 18 | object "Terraform" as tf #FACD62 { 19 | version >= 0.12 && < 0.13 20 | } 21 | 22 | object "OCI Terraform Provider" as tfprovider #94AFAF { 23 | version >= 3.27 24 | } 25 | 26 | object "oci-iam Module" as tfmodule #759C6C { 27 | version >= 2.0 28 | } 29 | 30 | tfmodule -d- tfprovider 31 | tfmodule -d- tf 32 | @enduml 33 | -------------------------------------------------------------------------------- /docs/diagrams/versions.svg: -------------------------------------------------------------------------------- 1 | Terraformversion >= 0.12 && < 0.13OCI Terraform Providerversion >= 3.27oci-iam Moduleversion >= 2.0 -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Create Compartment, Sub-compartment, Users, Group and Dynamic Group 2 | 3 | This example shows how to create a compartement and two sub-compartemnt. 4 | 5 | This example also shows how to create: 6 | 7 | - several users with a single module block, 8 | - a group and add users to it, 9 | - a policy pertaining to a compartment and group, 10 | - some more directives to show dynamic groups and policy for it. 11 | 12 | Notes: 13 | 14 | - The compartment resource internally resolves name collisions and returns a reference to the preexisting compartment. 15 | All resources created by this example can be deleted by using the `terraform destroy` command. 16 | - When using the oci-iam modules, or more generally when manipulating iam resources, **be sure to configure your oci provider to use the tenancy's home region**, as IAM resources can only be managed from the home region. 17 | - To combine this template with non-iam resources provisioned in a region different from your *home region*, you will need to use [provider aliases](https://www.terraform.io/docs/configuration/providers.html#alias-multiple-provider-configurations). 18 | 19 | ## Using this example 20 | 21 | - Create a "terraform.tfvars" file based on the provided template, "terraform.tfvars.template", and fill in the necessary info. 22 | - Initialize the directory: 23 | 24 | ```bash 25 | > terraform init 26 | ``` 27 | 28 | - Inspect what Terraform plans to do for the next `apply`: 29 | 30 | ```bash 31 | > terraform plan 32 | ``` 33 | 34 | - If proposed changes are what is intended, apply the current plan to Provision resources on OCI (if not, abort the operation and review the configuration): 35 | 36 | ```bash 37 | > terraform apply 38 | ``` 39 | 40 | Sample ouput: 41 | 42 | ```bash 43 | Apply complete! Resources: 11 added, 0 changed, 0 destroyed. 44 | 45 | Outputs: 46 | 47 | iam_compartment = { 48 | "description" = "compartment created by terraform" 49 | "name" = "tf_example_compartment" 50 | "ocid" = "ocid1.compartment.oc1..aaaaaaaa" 51 | "parent" = "ocid1.tenancy.oc1..aaaaaaaa" 52 | } 53 | iam_dynamic_group_name = tf_example_dynamic_group 54 | iam_group = [ 55 | { 56 | "tf_example_group" = "ocid1.group.oc1..aaaaaaaa" 57 | }, 58 | ] 59 | iam_subcompartment1 = { 60 | "description" = "subcompartment created below tf_example_compartment by terraform" 61 | "name" = "tf_example_subcompartment" 62 | "ocid" = "" 63 | "parent" = "" 64 | } 65 | iam_subcompartment2 = { 66 | "description" = "subcompartment created below tf_example_compartment by terraform" 67 | "name" = "tf_example_subcompartment2" 68 | "ocid" = "" 69 | "parent" = "" 70 | } 71 | iam_users = [ 72 | { 73 | "tf_example_user1@example.com" = "ocid1.user.oc1..aaaaaaaa" 74 | "tf_example_user2@example.com" = "ocid1.user.oc1..aaaaaaaa" 75 | "tf_example_user3@example.com" = "ocid1.user.oc1..aaaaaaaa" 76 | }, 77 | ] 78 | ``` 79 | -------------------------------------------------------------------------------- /examples/hierarchical_compartment_config.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | compartments: 5 | - compartment_name: compartment_level_1_a 6 | description: "level 1 a" 7 | freeform_tags: 8 | "Env": "Dev" 9 | "Billing": "Devbilling" 10 | enable_delete: true 11 | compartments: 12 | - compartment_name: compartment_level_2_a 13 | description: "level 2 a" 14 | enable_delete: true 15 | compartments: 16 | - compartment_name: compartment_level_3_1_a 17 | description: "level 3.1 a" 18 | enable_delete: true 19 | compartments: [] 20 | - compartment_name: compartment_level_3_2_a 21 | description: "level 3.2 a" 22 | enable_delete: true 23 | compartments: 24 | - compartment_name: compartment_level_4_a 25 | description: "level 4 a" 26 | enable_delete: true 27 | compartments: 28 | - compartment_name: compartment_level_5_a 29 | description: "level 5 a" 30 | enable_delete: true 31 | compartments: 32 | - compartment_name: compartment_level_6_a 33 | description: "level 6 a" 34 | enable_delete: true 35 | - compartment_name: compartment_level_1_b 36 | description: "level 1 b" 37 | enable_delete: true 38 | compartments: 39 | - compartment_name: compartment_level_2_b 40 | compartments: [] 41 | description: "level 2b" 42 | enable_delete: true 43 | freeform_tags: 44 | "Env": "Test" 45 | "Billing": "Testbilling" 46 | -------------------------------------------------------------------------------- /examples/hierarchical_compartments.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | /* 5 | * This example shows how to create a hierarchical compartments. 6 | * 7 | * The hierarchical_compartment_config.yaml contains the detailed structure of 8 | * compartments that needs to be provisioned. 9 | */ 10 | 11 | module "Hierarchical_compartment" { 12 | source = "oracle-terraform-modules/iam/oci//modules/iam-hierarchical-compartment" 13 | # version = "2.0.2" 14 | root_compartment_id = var.tenancy_ocid # define the parent compartment. Creation at tenancy root if omitted 15 | compartments = yamldecode(file("${path.module}/hierarchical_compartment_config.yaml"))["compartments"] 16 | } 17 | -------------------------------------------------------------------------------- /examples/main.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | variable "tenancy_ocid" {} 5 | variable "compartment_ocid" {} 6 | variable "user_ocid" {} 7 | variable "fingerprint" {} 8 | variable "private_key_path" {} 9 | variable "region" {} 10 | variable "homeregion" {} 11 | 12 | terraform { 13 | required_version = ">= 0.12, < 0.13" // this example is intended to run with Terraform v0.12 14 | required_providers { 15 | oci = { 16 | version = ">= 3.27, < 4.0" // force downloading oci-provider compatible with terraform v0.12 17 | } 18 | } 19 | } 20 | 21 | provider "oci" { 22 | tenancy_ocid = var.tenancy_ocid 23 | user_ocid = var.user_ocid 24 | fingerprint = var.fingerprint 25 | private_key_path = var.private_key_path 26 | region = var.homeregion 27 | } 28 | 29 | /* 30 | * This example shows how to create a compartement and two sub-compartemnt. 31 | * 32 | * This example also shows how to create: 33 | * - several users with a single module block, 34 | * - a group and add group members to it, 35 | * - a policy pertaining to a compartment and group, 36 | * - some more directives to show dynamic groups and policy for it. 37 | * 38 | * Note: The compartment resource internally resolves name collisions and returns a reference to the preexisting compartment. 39 | * All resources created by this example can be deleted by using the Terraform destroy command. 40 | */ 41 | 42 | module "iam_compartment" { 43 | source = "oracle-terraform-modules/iam/oci//modules/iam-compartment" 44 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 45 | # version = "x.x.x" 46 | tenancy_ocid = var.tenancy_ocid 47 | compartment_id = var.tenancy_ocid # define the parent compartment. Creation at tenancy root if omitted 48 | compartment_name = "tf_example_compartment" 49 | compartment_description = "compartment at root level created - terraformed" 50 | compartment_create = true # if false, a data source with a matching name is created instead 51 | enable_delete = true # if false, on `terraform destroy`, compartment is deleted from the terraform state but not from oci 52 | } 53 | 54 | module "iam_subcompartment1" { 55 | source = "oracle-terraform-modules/iam/oci//modules/iam-compartment" 56 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 57 | # version = "x.x.x" 58 | tenancy_ocid = var.tenancy_ocid 59 | compartment_id = module.iam_compartment.compartment_id # define the parent compartment. Here we make reference to the previous module 60 | compartment_name = "tf_example_subcompartment1" 61 | compartment_description = "subcompartment created below tf_example_compartment - terraformed" 62 | compartment_create = true # if false, a data source with a matching name is created instead 63 | enable_delete = true # if false, on `terraform destroy`, compartment is deleted from the terraform state but not from oci 64 | } 65 | 66 | module "iam_subcompartment2" { 67 | source = "oracle-terraform-modules/iam/oci//modules/iam-compartment" 68 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 69 | # version = "x.x.x" 70 | tenancy_ocid = var.tenancy_ocid 71 | compartment_id = module.iam_compartment.compartment_id # define the parent compartment. Here we make reference to the previous module 72 | compartment_name = "tf_example_subcompartment2" 73 | compartment_description = "subcompartment created below tf_example_compartment - terraformed" 74 | compartment_create = true # if false, a data source with a matching name is created instead 75 | enable_delete = true # if false, on `terraform destroy`, compartment is deleted from the terraform state but not from oci 76 | } 77 | 78 | module "iam_users" { 79 | source = "oracle-terraform-modules/iam/oci//modules/iam-user" 80 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 81 | # version = "x.x.x" 82 | tenancy_ocid = var.tenancy_ocid 83 | users = [ 84 | { # user1 85 | name = "tf_example_user1@example.com" 86 | description = "user1 created by terraform" 87 | email = null 88 | }, 89 | { # user2 90 | name = "tf_example_user2@example.com" 91 | description = "user2 created by terraform" 92 | email = "tf_example_user2@example.com" 93 | }, 94 | { # user3 95 | name = "tf_example_user3@example.com" 96 | description = "user3 created by terraform" 97 | email = "tf_example_user3@example.com" 98 | }, # add more users below if needed 99 | ] 100 | } 101 | 102 | module "iam_group" { 103 | source = "oracle-terraform-modules/iam/oci//modules/iam-group" 104 | version = "2.0.0" 105 | tenancy_ocid = var.tenancy_ocid 106 | group_name = "tf_example_group" 107 | group_description = "an example group - terraformed" 108 | user_ids = [element(module.iam_users.user_id, 0), element(module.iam_users.user_id, 1), element(module.iam_users.user_id, 2)] # a list of user ocids 109 | policy_name = "tf-example-policy" 110 | policy_compartment_id = module.iam_compartment.compartment_id 111 | policy_description = "policy created by terraform aaaaaaaaaah" 112 | policy_statements = [ 113 | "Allow group ${module.iam_group.group_name} to read instances in compartment tf_example_compartment", 114 | "Allow group ${module.iam_group.group_name} to inspect instances in compartment tf_example_compartment", 115 | ] 116 | } 117 | 118 | module "iam_dynamic_group" { 119 | source = "oracle-terraform-modules/iam/oci//modules/iam-dyanmic-group" 120 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 121 | # version = "x.x.x" 122 | tenancy_ocid = var.tenancy_ocid 123 | dynamic_group_name = "tf_example_dynamic_group" 124 | dynamic_group_description = "dynamic group created by terraform" 125 | matching_rule = "instance.compartment.id = '${module.iam_compartment.compartment_id}'" 126 | policy_compartment_id = module.iam_compartment.compartment_id 127 | policy_name = "tf-example-dynamic-policy" 128 | policy_description = "dynamic policy created by terraform" 129 | policy_statements = [ 130 | "Allow dynamic-group ${module.iam_dynamic_group.dynamic_group_name} to read instances in compartment tf_example_compartment", 131 | "Allow dynamic-group ${module.iam_dynamic_group.dynamic_group_name} to inspect instances in compartment tf_example_compartment", 132 | ] 133 | } 134 | -------------------------------------------------------------------------------- /examples/outputs.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | output "iam_compartment" { 5 | description = "compartment name, description, ocid, and parent ocid" 6 | value = { 7 | name = module.iam_compartment.compartment_name, 8 | description = module.iam_compartment.compartment_description, 9 | ocid = module.iam_compartment.compartment_id, 10 | parent = module.iam_compartment.parent_compartment_id 11 | } 12 | } 13 | 14 | output "iam_subcompartment1" { 15 | description = "compartment name, description, ocid, and parent ocid" 16 | value = { 17 | name = module.iam_subcompartment1.compartment_name, 18 | description = module.iam_subcompartment1.compartment_description, 19 | ocid = module.iam_subcompartment1.compartment_id, 20 | parent = module.iam_subcompartment1.parent_compartment_id 21 | } 22 | } 23 | 24 | output "iam_subcompartment2" { 25 | description = "compartment name, description, ocid, and parent ocid" 26 | value = { 27 | name = module.iam_subcompartment2.compartment_name, 28 | description = module.iam_subcompartment2.compartment_description, 29 | ocid = module.iam_subcompartment2.compartment_id, 30 | parent = module.iam_subcompartment1.parent_compartment_id 31 | } 32 | } 33 | output "iam_users" { 34 | description = "list of username and associated ocid" 35 | value = module.iam_users.name_ocid 36 | } 37 | 38 | output "iam_group" { 39 | description = "group name and associated ocid" 40 | value = module.iam_group.name_ocid 41 | } 42 | 43 | output "iam_dynamic_group_name" { 44 | description = "dynamic group name and associated ocid" 45 | value = module.iam_dynamic_group.name_ocid 46 | } 47 | 48 | output "compartment_ids_under_root" { 49 | description = "Compartment id list under root" 50 | value = module.Hierarchical_compartment.compartment_ids 51 | } 52 | -------------------------------------------------------------------------------- /examples/terraform.tfvars.sample: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | # OCI Authentication details 5 | tenancy_ocid = "" 6 | compartment_ocid = "" 7 | user_ocid = "" 8 | fingerprint = "" 9 | private_key_path = "" 10 | 11 | # Regions 12 | homeregion = "" 13 | region = "" 14 | 15 | -------------------------------------------------------------------------------- /modules/iam-compartment/README.md: -------------------------------------------------------------------------------- 1 | # modules/iam-compartment 2 | 3 | This [Terraform module](https://www.terraform.io/docs/modules/index.html) allows an [Oracle Cloud Infrastructure compartment](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingcompartments.htm) to be used in either read-only mode or read/write mode. You can switch between the two modes by setting the `compartment_create` argument to either `true` (a new resource will be created) or `false` (a data source filtered to the provided compartment name will be created). 4 | 5 | With the `enable_delete` argument (boolean: `true` or `false`), you can control the `terraform destroy` command behavior: 6 | 7 | - `true`: terraform will actually delete the compartment from OCI. 8 | - `false`: terraform will only remove the compartment from the configuration (the actual OCI resource is not deleted, only the terraform representation is deleted 9 | 10 | Below is the typical module block you should add to your configuration to create a compartment with this module. 11 | 12 | **IMPORTANT:** There is no version pinning of modules in the examples to lower documentation maintenance when releasing new module versions. It is a good practice to pin the module version to the exact version you are using in your code so that your infrastructure remains stable and predictible. 13 | 14 | ```hcl 15 | module "iam_compartment" { 16 | source = "oracle-terraform-modules/iam/oci//modules/iam-compartment" 17 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 18 | # version = "x.x.x" 19 | tenancy_ocid = var.tenancy_ocid 20 | compartment_id = var.tenancy_ocid 21 | compartment_name = "tf_example_compartment" 22 | compartment_description = "compartment created by terraform" 23 | compartment_create = true 24 | enable_delete = true 25 | } 26 | ``` 27 | 28 | The argument `compartment_id` defines the parent compartment of the defined compartment and takes an ocid as value: 29 | 30 | - to create or move a compartment at the root level, set `compartment_id` to the tenancy ocid, 31 | - to create or move a compartment at below another compartment, set `compartment_id` to the partent compartment ocid, 32 | 33 | ```hcl 34 | module "iam_subcompartment" { 35 | source = "oracle-terraform-modules/iam/oci//modules/iam-compartment" 36 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 37 | # version = "x.x.x" 38 | tenancy_ocid = var.tenancy_ocid 39 | compartment_id = module.iam_compartment.compartment_id 40 | compartment_name = "tf_example_subcompartment" 41 | compartment_description = "subcompartment created below tf_example_compartment by terraform" 42 | compartment_create = true 43 | enable_delete = true 44 | } 45 | ``` 46 | 47 | Check out the [examples](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/examples) for fully-working sample code. 48 | 49 | Note the following parameters: 50 | 51 | Argument | Description | Default 52 | --- | --- | --- 53 | tenancy_ocid | **[DEPRECATED]** (Required) Unique identifier (OCID) of the tenancy. | null 54 | compartment_id | (Required)(Updatable) The OCID of the parent compartment containing the compartment. | null 55 | compartment_name | (Required)(Updatable) The name you assign to the compartment. The name must be unique across all compartments in the parent compartment. | null 56 | compartment_description | (Required if compartment_create is true.)(Updatable) The description you assign to the compartment during creation. Does not have to be unique, and it's changeable. | null 57 | compartment_create | **[DEPRECATED]** (Optional) Specifies whether the module should create a compartment. If true, the compartment will be managed by the module. In this case, the user must have permission to create the compartment. If false, compartment data will be returned about any existing compartments. If no compartment is found, an empty string is returned for the compartment ID. | true 58 | enable_delete | If omitted or set to false the provider will implicitly import the compartment if there is a name collision, and will not actually delete the compartment on destroy or removal of the resource declaration. If set to true, the provider will throw an error on a name collision with another compartment, and will attempt to delete the compartment on destroy or removal of the resource declaration. | false 59 | -------------------------------------------------------------------------------- /modules/iam-compartment/main.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | ######################## 6 | # Compartment 7 | ######################## 8 | 9 | resource "oci_identity_compartment" "this" { 10 | count = var.compartment_create ? 1 : 0 11 | compartment_id = var.compartment_id != null ? var.compartment_id : var.tenancy_ocid 12 | name = var.compartment_name 13 | description = var.compartment_description 14 | enable_delete = var.enable_delete 15 | } 16 | 17 | data "oci_identity_compartments" "this" { 18 | count = var.compartment_create ? 0 : 1 19 | compartment_id = var.compartment_id 20 | 21 | filter { 22 | name = "name" 23 | values = [var.compartment_name] 24 | } 25 | } 26 | 27 | locals { 28 | compartment_ids = concat(flatten(data.oci_identity_compartments.this.*.compartments), [{ id = "" }]) 29 | parent_compartment_ids = concat(flatten(data.oci_identity_compartments.this.*.compartments), [{ compartment_id = "" }]) 30 | } 31 | -------------------------------------------------------------------------------- /modules/iam-compartment/outputs.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | output "compartment_id" { 6 | description = "Compartment ocid" 7 | // This allows the compartment ID to be retrieved from the resource if it exists, and if not to use the data source. 8 | value = var.compartment_create ? element(concat(oci_identity_compartment.this.*.id, [""]), 0) : lookup(local.compartment_ids[0], "id") 9 | } 10 | 11 | output "parent_compartment_id" { 12 | description = "Parent Compartment ocid" 13 | // This allows the compartment ID to be retrieved from the resource if it exists, and if not to use the data source. 14 | value = var.compartment_create ? element(concat(oci_identity_compartment.this.*.compartment_id, [""]), 0) : lookup(local.parent_compartment_ids[0], "compartment_id") 15 | } 16 | 17 | output "compartment_name" { 18 | description = "Compartment name" 19 | value = var.compartment_name 20 | } 21 | 22 | output "compartment_description" { 23 | description = "Compartment description" 24 | value = var.compartment_description 25 | } 26 | -------------------------------------------------------------------------------- /modules/iam-compartment/variables.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | variable "tenancy_ocid" { 6 | type = string 7 | description = "(Deprecated) The OCID of the tenancy." 8 | default = null 9 | } 10 | 11 | variable "compartment_id" { 12 | type = string 13 | description = "The OCID of the parent compartment containing the compartment. Allow for sub-compartments creation" 14 | default = null 15 | } 16 | 17 | variable "compartment_name" { 18 | type = string 19 | description = "The name you assign to the compartment during creation. The name must be unique across all compartments in the tenancy. " 20 | default = null 21 | } 22 | 23 | // The description is only used if compartment_create = true. 24 | variable "compartment_description" { 25 | type = string 26 | description = "The description you assign to the compartment. Does not have to be unique, and it's changeable. " 27 | default = null 28 | } 29 | 30 | variable "compartment_create" { 31 | type = bool 32 | description = "(Deprecated) Create the compartment or not. If true, the compartment will be managed by this module, and the user must have permissions to create the compartment; If false, compartment data will be returned about the compartment if it exists, if not found, then an empty string will be returned for the compartment ID." 33 | default = true 34 | } 35 | 36 | variable "enable_delete" { 37 | type = bool 38 | description = "Enable compartment delete on destroy. If true, compartment will be deleted when `terraform destroy` is executed; If false, compartment will not be deleted on `terraform destroy` execution" 39 | default = false 40 | } 41 | -------------------------------------------------------------------------------- /modules/iam-compartment/versions.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | terraform { 5 | required_providers { 6 | oci = { 7 | source = "oracle/oci" 8 | version = ">=4.67.3" 9 | } 10 | } 11 | required_version = ">= 1.0.0" 12 | } 13 | -------------------------------------------------------------------------------- /modules/iam-dynamic-group/README.md: -------------------------------------------------------------------------------- 1 | # modules/iam-dynamic-group 2 | 3 | This [Terraform module](https://www.terraform.io/docs/modules/index.html) defines an [Oracle Cloud Infrastructure Dynamic Group](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingdynamicgroups.htm). Optionally, you can: 4 | 5 | * add an OCI IAM policy for this dynamic group. [See How Policies Work](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policies.htm) and [Common Policies](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/commonpolicies.htm) for more information regarding the policy syntax. 6 | 7 | Below is the typical module block you should add to your configuration to create a compartment with this module. 8 | 9 | **IMPORTANT:** There is no version pinning of modules in the examples to lower documentation maintenance when releasing new module versions. It is a good practice to pin the module version to the exact version you are using in your code so that your infrastructure remains stable and predictible. 10 | 11 | ```hcl 12 | module "iam_dynamic_group" { 13 | source = "oracle-terraform-modules/iam/oci//modules/iam-dynamic-group" 14 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 15 | # version = "x.x.x" 16 | tenancy_ocid = "${var.tenancy_ocid}" 17 | dynamic_group_name = "tf_example_dynamic_group" 18 | dynamic_group_description = "dynamic group created by terraform" 19 | matching_rule = "instance.compartment.id = '${module.iam_compartment.compartment_id}'" 20 | policy_compartment_id = "${module.iam_compartment.compartment_id}" 21 | policy_name = "tf-example-dynamic-policy" 22 | policy_description = "dynamic policy created by terraform" 23 | policy_statements = ["Allow dynamic-group tf_example_dynamic_group to read instances in compartment tf_example_compartment"] 24 | } 25 | ``` 26 | 27 | Check out the [examples](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/examples) for fully-working sample code. 28 | 29 | Note the following parameters: 30 | 31 | Argument | Description | Default 32 | --- | --- | --- 33 | tenancy_ocid | (Required) Unique identifier (OCID) of the tenancy. | null 34 | dynamic_group_name | (Required) Name given to the dynamic group during creation. The name must be unique across all compartments in the tenancy and cannot be changed. | null 35 | dynamic_group_description | (Required if dynamic_group_create is true.)(Updatable) Description of the dynamic group. Does not have to be unique, and it's changeable. | null 36 | dynamic_group_create | **[DEPRECATED]** (Optional) Specifies whether the module should create a dynamic group. If true, the user must have permission to create a dynamic group. If false, data is returned for any existing dynamic groups, and an empty string is returned for the dynamic group ID. | true 37 | matching_rule | (Required if dynamic_group_create is true.)(Updatable) The matching rule to dynamically match an instance certificate to this dynamic group. For rule syntax, see [Managing Dynamic Groups](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingdynamicgroups.htm). | null 38 | policy_name | (Optional) The name you assign to the IAM policy. The name you assign to the IAM policy. The name must be unique across all policies in the tenancy and cannot be changed. | null 39 | policy_description | (Required if policy_name is set)(Updatable) The description you assign to the policy during creation. Does not have to be unique, and it's changeable. | null 40 | policy_statements | (Required if policy_name is set)(Updatable) An array of policy statements written in the policy language. | null 41 | -------------------------------------------------------------------------------- /modules/iam-dynamic-group/main.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | ######################## 6 | # Dynamic Group 7 | ######################## 8 | resource "oci_identity_dynamic_group" "this" { 9 | count = var.dynamic_group_create == true ? 1 : 0 10 | compartment_id = var.tenancy_ocid 11 | name = var.dynamic_group_name 12 | description = var.dynamic_group_description 13 | matching_rule = var.matching_rule 14 | } 15 | 16 | data "oci_identity_dynamic_groups" "this" { 17 | count = var.dynamic_group_create == false ? 1 : 0 18 | compartment_id = var.tenancy_ocid 19 | 20 | filter { 21 | name = "name" 22 | values = [var.dynamic_group_name] 23 | } 24 | } 25 | 26 | locals { 27 | dynamic_group_ids = concat(flatten(data.oci_identity_dynamic_groups.this.*.dynamic_groups), [{ id = "" }]) 28 | } 29 | 30 | ######################## 31 | # Dynamic Group Policy 32 | ######################## 33 | resource "oci_identity_policy" "this" { 34 | count = var.policy_name != null ? 1 : 0 35 | depends_on = [oci_identity_dynamic_group.this] 36 | name = var.policy_name 37 | description = var.policy_description 38 | compartment_id = var.policy_compartment_id 39 | statements = var.policy_statements 40 | } 41 | -------------------------------------------------------------------------------- /modules/iam-dynamic-group/outputs.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | output "dynamic_group_id" { 6 | description = "Dynamic Group ocid" 7 | value = var.dynamic_group_create ? element(concat(oci_identity_dynamic_group.this.*.id, [""]), 0) : lookup(local.dynamic_group_ids[0], "id") 8 | } 9 | 10 | output "dynamic_group_name" { 11 | description = "Dynamic Group name" 12 | value = var.dynamic_group_name 13 | } 14 | 15 | output "name_ocid" { 16 | value = zipmap(oci_identity_dynamic_group.this[*].name, oci_identity_dynamic_group.this[*].id) 17 | description = "Dynamic Group name and associated OCID" 18 | } 19 | output "dynamic_group_policy_name" { 20 | description = "Dynamic Group policy name" 21 | value = var.policy_name 22 | } 23 | -------------------------------------------------------------------------------- /modules/iam-dynamic-group/variables.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | variable "tenancy_ocid" { 6 | type = string 7 | description = "The OCID of the tenancy." 8 | default = null 9 | } 10 | 11 | variable "dynamic_group_name" { 12 | type = string 13 | description = "The name you assign to the group during creation. The name must be unique across all compartments in the tenancy. " 14 | default = null 15 | } 16 | 17 | variable "dynamic_group_description" { 18 | type = string 19 | description = "The description you assign to the Group. Does not have to be unique, and it's changeable. " 20 | default = null 21 | } 22 | 23 | variable "dynamic_group_create" { 24 | type = bool 25 | description = "(Deprecated) Create the dynamic group or not. If true, the user must have permissions to create the group; If false, group data will be returned about the group if it exists, if not found, then an empty string will be returned for the group ID." 26 | default = true 27 | } 28 | 29 | variable "matching_rule" { 30 | type = string 31 | description = "Define a matching rule or a set of matching rules to define the group members." 32 | default = null 33 | } 34 | 35 | variable "policy_name" { 36 | type = string 37 | description = "The name you assign to the policy during creation. " 38 | default = null 39 | } 40 | 41 | variable "policy_description" { 42 | type = string 43 | description = "The description you assign to the policy. Does not have to be unique, and it's changeable. " 44 | default = null 45 | } 46 | 47 | variable "policy_statements" { 48 | type = list(string) 49 | description = "Define policy consists of one or more policy statements. " 50 | default = null 51 | } 52 | 53 | variable "policy_compartment_id" { 54 | type = string 55 | description = "The compartment id assign to policy." 56 | default = null 57 | } 58 | -------------------------------------------------------------------------------- /modules/iam-dynamic-group/versions.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | terraform { 5 | required_providers { 6 | oci = { 7 | source = "oracle/oci" 8 | version = ">=4.67.3" 9 | } 10 | } 11 | required_version = ">= 1.0.0" 12 | } 13 | -------------------------------------------------------------------------------- /modules/iam-group/README.md: -------------------------------------------------------------------------------- 1 | # modules/iam-group 2 | 3 | This [Terraform module](https://www.terraform.io/docs/modules/index.html) defines an [Oracle Cloud Infrastructure Group](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managinggroups.htm). Optionally, you can: 4 | 5 | * add a list of users as member to the created group, 6 | * add an OCI IAM policy. [See How Policies Work](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policies.htm) and [Common Policies](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/commonpolicies.htm) for more information regarding the policy syntax. 7 | 8 | Below is the typical module block you should add to your configuration to create a compartment with this module. 9 | 10 | **IMPORTANT:** There is no version pinning of modules in the examples to lower documentation maintenance when releasing new module versions. It is a good practice to pin the module version to the exact version you are using in your code so that your infrastructure remains stable and predictible. 11 | 12 | ```hcl 13 | module "iam_group" { 14 | source = "oracle-terraform-modules/iam/oci//modules/iam-group" 15 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 16 | # version = "x.x.x" 17 | tenancy_ocid = var.tenancy_ocid # required 18 | group_name = "tf_example_group" # required 19 | group_description = "an example group - terraformed" # required 20 | user_ids = [var.user1_id,var.user2_id,var.user3_id] 21 | policy_compartment_id = var.tenancy_ocid 22 | policy_name = "tf-example-policy" # optional 23 | policy_description = "policy created by terraform" # optional 24 | policy_statements = [ # optional 25 | "Allow group tf_example_group to read instances in compartment tf_example_compartment", 26 | "Allow group tf_example_group to inspect instances in compartment tf_example_compartment", 27 | ] 28 | } 29 | ``` 30 | 31 | Check out the [examples](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/examples) folder for fully-working sample code. 32 | 33 | Note the following parameters: 34 | 35 | Argument | Description | Default 36 | --- | --- | --- 37 | tenancy_ocid | (Required) Unique identifier (OCID) of the tenancy. | null 38 | group_name | (Required) The name you assign to the IAM group when created. The name must be unique across all groups in the tenancy and cannot be changed. | null 39 | group_description | (Required if group_create is true.)(Updatable) Description of the IAM group. Does not have to be unique, and it's changeable. | null 40 | group_create | **[DEPRECATED]** (Optional) Specifies whether the module should create the group. If true, the user must have permission to create a group. If false, group data is returned for all existing groups. If no groups are found, an empty string is returned for the group ID. | true 41 | user_ids | (Optional)(Updatable) List of user ocids to add as group member. | null 42 | policy_name | (Optional) The name you assign to the IAM policy. The name must be unique across all policies in the tenancy and cannot be changed. | null 43 | policy_compartment | (Required, if policy_name is set) The OCID of the compartment containing the policy. Cannot be changed (current API limitation.) | null 44 | policy_description | (Required, if policy_name is set)(Updatable) The description you assign to the policy during creation. Does not have to be unique, and it's changeable. | null 45 | policy_statements | (Required if policy_name is set)(Updatable) An array of policy statements written in the policy language. | null 46 | -------------------------------------------------------------------------------- /modules/iam-group/main.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | ######################## 5 | # Group 6 | ######################## 7 | resource "oci_identity_group" "this" { 8 | count = var.group_create == true ? 1 : 0 9 | compartment_id = var.tenancy_ocid 10 | name = var.group_name 11 | description = var.group_description 12 | } 13 | 14 | data "oci_identity_groups" "this" { 15 | count = var.group_create == false ? 1 : 0 16 | compartment_id = var.tenancy_ocid 17 | 18 | filter { 19 | name = "name" 20 | values = [var.group_name] 21 | } 22 | } 23 | 24 | locals { 25 | group_ids = concat(flatten(data.oci_identity_groups.this.*.groups), [{ "id" = "" }]) 26 | } 27 | 28 | ######################## 29 | # Add user to a group 30 | ######################## 31 | resource "oci_identity_user_group_membership" "this" { 32 | count = var.user_ids == null ? 0 : length(var.user_ids) 33 | user_id = var.user_ids[count.index] 34 | group_id = var.group_create ? element(concat(oci_identity_group.this.*.id, [""]), 0) : lookup(local.group_ids[0], "id") 35 | } 36 | 37 | ######################## 38 | # Group Policy 39 | ######################## 40 | resource "oci_identity_policy" "this" { 41 | count = var.policy_name != null ? 1 : 0 42 | depends_on = [oci_identity_group.this] 43 | name = var.policy_name 44 | description = var.policy_description 45 | compartment_id = var.policy_compartment_id 46 | statements = var.policy_statements 47 | } 48 | -------------------------------------------------------------------------------- /modules/iam-group/outputs.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | output "group_id" { 5 | description = "Group ocid" 6 | value = var.group_create ? element(concat(oci_identity_group.this.*.id, [""]), 0) : lookup(local.group_ids[0], "id") 7 | } 8 | 9 | output "group_name" { 10 | description = "Group name" 11 | value = var.group_name 12 | } 13 | 14 | output "name_ocid" { 15 | value = zipmap(oci_identity_group.this[*].name, oci_identity_group.this[*].id) 16 | description = "group name and associated OCID" 17 | } 18 | 19 | output "group_description" { 20 | description = "Group description" 21 | value = var.group_description 22 | } 23 | 24 | output "group_policy_name" { 25 | description = "Group policy name" 26 | value = var.policy_name 27 | } 28 | -------------------------------------------------------------------------------- /modules/iam-group/variables.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | variable "tenancy_ocid" { 5 | type = string 6 | description = "The OCID of the tenancy." 7 | default = null 8 | } 9 | 10 | variable "group_name" { 11 | type = string 12 | description = "The name you assign to the group during creation. The name must be unique across all compartments in the tenancy." 13 | default = null 14 | } 15 | 16 | // The description is only used if group_create = true. 17 | variable "group_description" { 18 | type = string 19 | description = "The description you assign to the Group. Does not have to be unique, and it's changeable. " 20 | default = null 21 | } 22 | 23 | variable "group_create" { 24 | type = bool 25 | description = "(Deprecated) Create the group or not. If true, the user must have permissions to create the group; If false, group data will be returned about the group if it exists, if not found, then an empty string will be returned for the group ID." 26 | default = true 27 | } 28 | 29 | variable "user_ids" { 30 | type = list(string) 31 | description = "List of user ocids to be added as group member" 32 | default = null 33 | } 34 | 35 | variable "policy_name" { 36 | type = string 37 | description = "The name you assign to the policy during creation. " 38 | default = null 39 | } 40 | 41 | variable "policy_description" { 42 | type = string 43 | description = "The description you assign to the policy. Does not have to be unique, and it's changeable. " 44 | default = null 45 | } 46 | 47 | variable "policy_statements" { 48 | type = list(string) 49 | description = "Define policy consists of one or more policy statements. " 50 | default = null 51 | } 52 | 53 | variable "policy_compartment_id" { 54 | type = string 55 | description = "The compartment id where policy is created." 56 | default = null 57 | } -------------------------------------------------------------------------------- /modules/iam-group/versions.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | terraform { 5 | required_providers { 6 | oci = { 7 | source = "oracle/oci" 8 | version = ">=4.67.3" 9 | } 10 | } 11 | required_version = ">= 1.0.0" 12 | } 13 | -------------------------------------------------------------------------------- /modules/iam-hierarchical-compartment/README.md: -------------------------------------------------------------------------------- 1 | 2 | # modules/iam-hierarchical-compartment 3 | 4 | This [Terraform module](https://www.terraform.io/docs/modules/index.html) allows an [Oracle Cloud Infrastructure compartment](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingcompartments.htm) to be created hierarchically upto 6-level deep from the root compartment. 5 | 6 | ## Example 7 | 8 | ```hcl 9 | module "Hierarchical_compartment" { 10 | source = "oracle-terraform-modules/iam/oci//modules/iam-hierarchical-compartment" 11 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 12 | # version = "x.x.x" 13 | root_compartment_id = var.tenancy_ocid # define the parent compartment. Creation at tenancy root if omitted 14 | compartments = yamldecode(file("${path.module}/hierarchical_compartment_config.yaml"))["compartments"] # place the yaml file in the same module path 15 | } 16 | ``` 17 | 18 | ```yaml 19 | compartments: 20 | - compartment_name: compartment_level_1_a 21 | description: "level 1 a" 22 | freeform_tags: 23 | "Env": "Dev" 24 | "Billing": "Devbilling" 25 | defined_tags: 26 | "Operations.CostCenter": "42" 27 | enable_delete: true 28 | compartments: 29 | - compartment_name: compartment_level_2_a 30 | description: "level 2 a" 31 | enable_delete: true 32 | compartments: 33 | - compartment_name: compartment_level_3_1_a 34 | description: "level 3.1 a" 35 | enable_delete: true 36 | compartments: [] 37 | - compartment_name: compartment_level_3_2_a 38 | description: "level 3.2 a" 39 | enable_delete: true 40 | compartments: 41 | - compartment_name: compartment_level_4_a 42 | description: "level 4 a" 43 | enable_delete: true 44 | compartments: 45 | - compartment_name: compartment_level_5_a 46 | description: "level 5 a" 47 | enable_delete: true 48 | compartments: 49 | - compartment_name: compartment_level_6_a 50 | description: "level 6 a" 51 | enable_delete: true 52 | - compartment_name: compartment_level_1_b 53 | description: "level 1 b" 54 | enable_delete: true 55 | compartments: 56 | - compartment_name: compartment_level_2_b 57 | compartments: [] 58 | description: "level 2b" 59 | enable_delete: true 60 | freeform_tags: 61 | "Env": "Test" 62 | "Billing": "Testbilling" 63 | 64 | ``` 65 | 66 | Check out the [examples](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/examples) for fully-working sample code. 67 | 68 | ## Requirements 69 | 70 | | Name | Version | 71 | |------|---------| 72 | | [terraform](#requirement\_terraform) | >= 1.0.0 | 73 | | [oci](#requirement\_oci) | >=4.67.3 | 74 | 75 | ## Providers 76 | 77 | | Name | Version | 78 | |------|---------| 79 | | [oci](#provider\_oci) | >=4.67.3 | 80 | 81 | ## Modules 82 | 83 | No modules. 84 | 85 | ## Resources 86 | 87 | | Name | Type | 88 | |------|------| 89 | | [oci_identity_compartment.compartment_level_1](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_compartment) | resource | 90 | | [oci_identity_compartment.compartment_level_2](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_compartment) | resource | 91 | | [oci_identity_compartment.compartment_level_3](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_compartment) | resource | 92 | | [oci_identity_compartment.compartment_level_4](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_compartment) | resource | 93 | | [oci_identity_compartment.compartment_level_5](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_compartment) | resource | 94 | | [oci_identity_compartment.compartment_level_6](https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/identity_compartment) | resource | 95 | 96 | ## Inputs 97 | 98 | | Name | Description | Type | Default | Required | 99 | |------|-------------|------|---------|:--------:| 100 | | [compartments](#input\_compartments) | Hierarchical Compartments | `any` | n/a | yes | 101 | | [root\_compartment\_id](#input\_root\_compartment\_id) | Target compartment id which is considered as root | `string` | n/a | yes | 102 | 103 | ## Outputs 104 | 105 | | Name | Description | 106 | |------|-------------| 107 | | [compartment\_ids](#output\_compartment\_ids) | Compartment ID's | 108 | -------------------------------------------------------------------------------- /modules/iam-hierarchical-compartment/main.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | locals { 6 | compartment_level_1 = flatten(setsubtract([for entry1 in var.compartments : { 7 | compartment_name = entry1.compartment_name 8 | defined_tags = lookup(entry1, "defined_tags", null) 9 | description = entry1.description 10 | freeform_tags = lookup(entry1, "freeform_tags", {}) 11 | enable_delete = lookup(entry1, "enable_delete", false) }], [])) 12 | 13 | compartment_level_2 = flatten(setsubtract([for entry1 in var.compartments : [for entry2 in entry1.compartments : { 14 | compartment_name = entry2.compartment_name 15 | defined_tags = lookup(entry2, "defined_tags", null) 16 | description = entry2.description 17 | freeform_tags = lookup(entry2, "freeform_tags", {}) 18 | parent_compartment = entry1.compartment_name 19 | enable_delete = lookup(entry2, "enable_delete", false) }]], [])) 20 | 21 | compartment_level_3 = flatten(setsubtract([for entry1 in var.compartments : [for entry2 in entry1.compartments : 22 | [for entry3 in entry2.compartments : { 23 | compartment_name = entry3.compartment_name 24 | defined_tags = lookup(entry3, "defined_tags", null) 25 | description = entry3.description 26 | freeform_tags = lookup(entry3, "freeform_tags", {}) 27 | parent_compartment = "${entry1.compartment_name}/${entry2.compartment_name}" 28 | enable_delete = lookup(entry3, "enable_delete", false) }]]], [])) 29 | 30 | compartment_level_4 = flatten(setsubtract([for entry1 in var.compartments : [for entry2 in entry1.compartments : 31 | [for entry3 in entry2.compartments : [for entry4 in entry3.compartments : { 32 | compartment_name = entry4.compartment_name 33 | defined_tags = lookup(entry4, "defined_tags", null) 34 | description = entry4.description 35 | freeform_tags = lookup(entry4, "freeform_tags", {}) 36 | parent_compartment = "${entry1.compartment_name}/${entry2.compartment_name}/${entry3.compartment_name}" 37 | enable_delete = lookup(entry4, "enable_delete", false) }]]]], [])) 38 | 39 | compartment_level_5 = flatten(setsubtract([for entry1 in var.compartments : [for entry2 in entry1.compartments : 40 | [for entry3 in entry2.compartments : [for entry4 in entry3.compartments : 41 | [for entry5 in entry4.compartments : { 42 | compartment_name = entry5.compartment_name 43 | defined_tags = lookup(entry5, "defined_tags", null) 44 | description = entry5.description 45 | freeform_tags = lookup(entry5, "freeform_tags", {}) 46 | parent_compartment = "${entry1.compartment_name}/${entry2.compartment_name}/${entry3.compartment_name}/${entry4.compartment_name}" 47 | enable_delete = lookup(entry5, "enable_delete", false) }]]]]], [])) 48 | 49 | compartment_level_6 = flatten(setsubtract([for entry1 in var.compartments : [for entry2 in entry1.compartments : 50 | [for entry3 in entry2.compartments : [for entry4 in entry3.compartments : 51 | [for entry5 in entry4.compartments : [for entry6 in entry5.compartments : { 52 | compartment_name = entry6.compartment_name 53 | defined_tags = lookup(entry6, "defined_tags", null) 54 | description = entry6.description 55 | freeform_tags = lookup(entry6, "freeform_tags", {}) 56 | parent_compartment = "${entry1.compartment_name}/${entry2.compartment_name}/${entry3.compartment_name}/${entry4.compartment_name}/${entry5.compartment_name}" 57 | enable_delete = lookup(entry6, "enable_delete", false) }]]]]]], [])) 58 | } 59 | 60 | 61 | 62 | 63 | resource "oci_identity_compartment" "compartment_level_1" { 64 | for_each = { for entry in local.compartment_level_1 : entry.compartment_name => entry } 65 | compartment_id = var.root_compartment_id 66 | description = each.value["description"] 67 | name = each.value["compartment_name"] 68 | defined_tags = each.value["defined_tags"] 69 | freeform_tags = each.value["freeform_tags"] 70 | enable_delete = each.value["enable_delete"] 71 | } 72 | 73 | resource "oci_identity_compartment" "compartment_level_2" { 74 | for_each = { for entry in local.compartment_level_2 : "${entry.parent_compartment}/${entry.compartment_name}" => entry } 75 | compartment_id = oci_identity_compartment.compartment_level_1[each.value["parent_compartment"]].id 76 | description = each.value["description"] 77 | name = each.value["compartment_name"] 78 | defined_tags = each.value["defined_tags"] 79 | freeform_tags = each.value["freeform_tags"] 80 | enable_delete = each.value["enable_delete"] 81 | } 82 | 83 | resource "oci_identity_compartment" "compartment_level_3" { 84 | for_each = { for entry in local.compartment_level_3 : "${entry.parent_compartment}/${entry.compartment_name}" => entry } 85 | compartment_id = oci_identity_compartment.compartment_level_2[each.value["parent_compartment"]].id 86 | description = each.value["description"] 87 | name = each.value["compartment_name"] 88 | defined_tags = each.value["defined_tags"] 89 | freeform_tags = each.value["freeform_tags"] 90 | enable_delete = each.value["enable_delete"] 91 | } 92 | 93 | resource "oci_identity_compartment" "compartment_level_4" { 94 | for_each = { for entry in local.compartment_level_4 : "${entry.parent_compartment}/${entry.compartment_name}" => entry } 95 | compartment_id = oci_identity_compartment.compartment_level_3[each.value["parent_compartment"]].id 96 | description = each.value["description"] 97 | name = each.value["compartment_name"] 98 | defined_tags = each.value["defined_tags"] 99 | freeform_tags = each.value["freeform_tags"] 100 | enable_delete = each.value["enable_delete"] 101 | } 102 | 103 | resource "oci_identity_compartment" "compartment_level_5" { 104 | for_each = { for entry in local.compartment_level_5 : "${entry.parent_compartment}/${entry.compartment_name}" => entry } 105 | compartment_id = oci_identity_compartment.compartment_level_4[each.value["parent_compartment"]].id 106 | description = each.value["description"] 107 | name = each.value["compartment_name"] 108 | defined_tags = each.value["defined_tags"] 109 | freeform_tags = each.value["freeform_tags"] 110 | enable_delete = each.value["enable_delete"] 111 | } 112 | 113 | resource "oci_identity_compartment" "compartment_level_6" { 114 | for_each = { for entry in local.compartment_level_6 : "${entry.parent_compartment}/${entry.compartment_name}" => entry } 115 | compartment_id = oci_identity_compartment.compartment_level_5[each.value["parent_compartment"]].id 116 | description = each.value["description"] 117 | name = each.value["compartment_name"] 118 | defined_tags = each.value["defined_tags"] 119 | freeform_tags = each.value["freeform_tags"] 120 | enable_delete = each.value["enable_delete"] 121 | } 122 | -------------------------------------------------------------------------------- /modules/iam-hierarchical-compartment/outputs.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | locals { 6 | compartment_ids = merge(concat( 7 | [for entry in local.compartment_level_1 : { 8 | (entry.compartment_name) = oci_identity_compartment.compartment_level_1[entry.compartment_name].id }], 9 | [for entry in local.compartment_level_2 : { 10 | (join("/", [entry.parent_compartment, entry.compartment_name])) = oci_identity_compartment.compartment_level_2["${entry.parent_compartment}/${entry.compartment_name}"].id }], 11 | [for entry in local.compartment_level_3 : { 12 | (join("/", [entry.parent_compartment, entry.compartment_name])) = oci_identity_compartment.compartment_level_3["${entry.parent_compartment}/${entry.compartment_name}"].id }], 13 | [for entry in local.compartment_level_4 : { 14 | (join("/", [entry.parent_compartment, entry.compartment_name])) = oci_identity_compartment.compartment_level_4["${entry.parent_compartment}/${entry.compartment_name}"].id }], 15 | [for entry in local.compartment_level_5 : { 16 | (join("/", [entry.parent_compartment, entry.compartment_name])) = oci_identity_compartment.compartment_level_5["${entry.parent_compartment}/${entry.compartment_name}"].id }], 17 | [for entry in local.compartment_level_6 : { 18 | (join("/", [entry.parent_compartment, entry.compartment_name])) = oci_identity_compartment.compartment_level_6["${entry.parent_compartment}/${entry.compartment_name}"].id }])...) 19 | } 20 | 21 | output "compartment_ids" { 22 | value = local.compartment_ids 23 | description = "Compartment ID's" 24 | } 25 | -------------------------------------------------------------------------------- /modules/iam-hierarchical-compartment/variables.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | variable "compartments" { 6 | type = any 7 | description = "Hierarchical Compartments" 8 | } 9 | 10 | variable "root_compartment_id" { 11 | type = string 12 | description = "Target compartment id which is considered as root" 13 | } 14 | -------------------------------------------------------------------------------- /modules/iam-hierarchical-compartment/versions.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | 5 | terraform { 6 | required_providers { 7 | oci = { 8 | source = "oracle/oci" 9 | version = ">=4.67.3" 10 | } 11 | } 12 | required_version = ">= 1.0.0" 13 | } 14 | -------------------------------------------------------------------------------- /modules/iam-user/README.md: -------------------------------------------------------------------------------- 1 | # modules/iam-user 2 | 3 | This [Terraform module](https://www.terraform.io/docs/modules/index.html) creates a list of [Oracle Cloud Infrastructure IAM users](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingusers.htm). Fedetated users are currently not supported by this module. 4 | 5 | In its current version, the module is limited to create each user with a description (required) and an e-mail (optional). Future versions of the module may support more parameters (API Keys, Tokens, Secret Keys, etc... ). 6 | 7 | Below is the typical module block you should add to your configuration to create a compartment with this module. 8 | 9 | **IMPORTANT:** There is no version pinning of modules in the examples to lower documentation maintenance when releasing new module versions. It is a good practice to pin the module version to the exact version you are using in your code so that your infrastructure remains stable and predictible. 10 | 11 | ```hcl 12 | module "iam_users" { 13 | source = "oracle-terraform-modules/iam/oci//modules/iam-user" 14 | # Pinning each module to a specific version is highly advisable. Please adjust and uncomment the line below 15 | # version = "x.x.x" 16 | tenancy_ocid = var.tenancy_ocid # required 17 | users = [ # a list of users 18 | { # user1 19 | name = "tf_example_user1@example.com" # required 20 | description = "user1 - terraformed" # required 21 | email = null # set to null if you don't want to provide an email 22 | }, 23 | { # user2 24 | name = "tf_example_user2@example.com" 25 | description = "user2 - terraformed" 26 | email = "tf_example_user2@example.com" 27 | }, 28 | { # user3 29 | name = "tf_example_user3@example.com" 30 | description = "user3 - terraformed" 31 | email = "tf_example_user3@example.com" 32 | },# add more users below as needed 33 | ] 34 | } 35 | ``` 36 | 37 | Check out the [examples](https://github.com/oracle-terraform-modules/terraform-oci-iam/tree/master/examples) folder for fully-working sample code. 38 | 39 | Note the following parameters for the module: 40 | 41 | Argument | Description | Default 42 | --- | --- | --- 43 | tenancy_ocid | (Required) Unique identifier (OCID) of the tenancy. Users may only be created at the root of the tenancy. | null 44 | users | (Required) A list of users to create | null 45 | 46 | Each User element is a map with up to three keys: 47 | 48 | Argument | Description | Default 49 | --- | --- | --- 50 | name | (Required) The name you assign to the user during creation. The name must be unique across all users in the tenancy and cannot be changed. | null 51 | description | (Required)(Updatable) Description you assign to the user during creation. Does not have to be unique, and it's changeable. | null 52 | email | (Required)(Updatable) The email address you assign to the user during creation. Has to be unique across the tenancy. Set it to null if you don't want to provide an email. | null 53 | -------------------------------------------------------------------------------- /modules/iam-user/main.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | ######################## 5 | # User 6 | ######################## 7 | resource "oci_identity_user" "this" { 8 | count = length(var.users) 9 | compartment_id = var.tenancy_ocid 10 | name = var.users[count.index].name 11 | description = var.users[count.index].description 12 | email = var.users[count.index].email == null ? "" : var.users[count.index].email 13 | } 14 | 15 | -------------------------------------------------------------------------------- /modules/iam-user/outputs.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | output "name_ocid" { 5 | value = zipmap(oci_identity_user.this[*].name, oci_identity_user.this[*].id) 6 | description = "list of username and associated OCID" 7 | } 8 | 9 | output "names" { 10 | value = oci_identity_user.this[*].name 11 | description = "list of usernames" 12 | } 13 | 14 | output "user_description" { 15 | value = oci_identity_user.this[*].description 16 | description = "list of users descriptions" 17 | } 18 | 19 | output "user_id" { 20 | value = oci_identity_user.this[*].id 21 | description = "list of users OCID" 22 | } -------------------------------------------------------------------------------- /modules/iam-user/variables.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | variable "tenancy_ocid" { 5 | type = string 6 | description = "The OCID of the tenancy." 7 | default = null 8 | } 9 | 10 | variable users { 11 | description = "The name and description you assign to the user during creation. The name must be unique across all compartments in the tenancy. " 12 | type = list(object({ 13 | name = string 14 | description = string 15 | email = string 16 | })) 17 | default = null 18 | } 19 | -------------------------------------------------------------------------------- /modules/iam-user/versions.tf: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, 2025, Oracle and/or its affiliates. 2 | // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl 3 | 4 | terraform { 5 | required_providers { 6 | oci = { 7 | source = "oracle/oci" 8 | version = ">=4.67.3" 9 | } 10 | } 11 | required_version = ">= 1.0.0" 12 | } 13 | --------------------------------------------------------------------------------