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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .web-docs/components/builder/oci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,12 @@ based on which authentication method is used.
Principals](https://docs.cloud.oracle.com/en-us/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm)
instead of User Principals. If this key is set to true, setting any one of the `access_cfg_file`,
`access_cfg_file_account`, `region`, `tenancy_ocid`, `user_ocid`, `key_file`, `fingerprint`,
`pass_phrase` parameters will cause an invalid configuration error.
`pass_phrase`, or `use_resource_principals` parameters will cause an invalid configuration error.
Defaults to `false`.

- `use_resource_principals` (boolean) - (Optional) Use Resource Principals for authentication. Resource Principals is a capability in Oracle Cloud Infrastructure Identity and Access Management (IAM) that allows resources (such as Functions, Data Flow applications, and API Gateways) to make service calls to other OCI services. This attribute is mutually exclusive with `access_cfg_file`, `access_cfg_file_account`, `user_ocid`, `tenancy_ocid`, `region`, `fingerprint`, `key_file`, `pass_phrase`, and `use_instance_principals`. Defaults to `false`.
To use resource principals, the resource running Packer (e.g., a Compute instance, a Function) must be part of a [Dynamic Group](https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/managingdynamicgroups.htm) that has appropriate [Policies](https://docs.oracle.com/en-us/iaas/Content/Identity/Concepts/policygetstarted.htm) granting it permissions to manage resources (e.g., launch instances, create images).

- `access_cfg_file` (string) - The path to the [OCI config
file](https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/sdkconfig.htm).
This parameter is _optional_ when using token-based authentication.
Expand Down
67 changes: 49 additions & 18 deletions builder/oci/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,19 @@ type Config struct {
// - PassPhrase
InstancePrincipals bool `mapstructure:"use_instance_principals"`

// Resource Principals (OPTIONAL)
// If set to true the following can't have non empty values
// - AccessCfgFile
// - AccessCfgFileAccount
// - UserID
// - TenancyID
// - Region
// - Fingerprint
// - KeyFile
// - PassPhrase
// - InstancePrincipals
UseResourcePrincipals bool `mapstructure:"use_resource_principals"`

// If true, Packer will not create the image. Useful for setting to `true`
// during a build test stage. Default `false`.
SkipCreateImage bool `mapstructure:"skip_create_image" required:"false"`
Expand Down Expand Up @@ -187,12 +200,19 @@ func (c *Config) Prepare(raws ...interface{}) error {

var tenancyOCID string

if c.InstancePrincipals {
// We could go through all keys in one go and report that the below set
// of keys cannot coexist with use_instance_principals but decided to
// split them and report them seperately so that the user sees the specific
// key involved.
var message string = " cannot be present when use_instance_principals is set to true."
if c.InstancePrincipals && c.UseResourcePrincipals {
errs = packersdk.MultiErrorAppend(errs, errors.New("use_instance_principals and use_resource_principals cannot both be true"))
}

if c.InstancePrincipals || c.UseResourcePrincipals {
var authType string
if c.InstancePrincipals {
authType = "use_instance_principals"
} else {
authType = "use_resource_principals"
}

var message string = fmt.Sprintf(" cannot be present when %s is set to true.", authType)
if c.AccessCfgFile != "" {
errs = packersdk.MultiErrorAppend(errs, errors.New("access_cfg_file"+message))
}
Expand All @@ -217,22 +237,33 @@ func (c *Config) Prepare(raws ...interface{}) error {
if c.PassPhrase != "" {
errs = packersdk.MultiErrorAppend(errs, errors.New("pass_phrase"+message))
}
// This check is used to facilitate testing. During testing a Mock struct
// is assigned to c.configProvider otherwise testing fails because Instance
// Principals cannot be obtained.

if c.configProvider == nil {
// Even though the previous configuration checks might fail we don't want
// to skip this step. It seems that the logic behind the checks in this
// file is to check everything even getting the configProvider.
c.configProvider, err = ociauth.InstancePrincipalConfigurationProvider()
if err != nil {
return err
if c.InstancePrincipals {
c.configProvider, err = ociauth.InstancePrincipalConfigurationProvider()
if err != nil {
// Surface the error if we can't get a config provider.
// This typically happens when not running on an OCI instance.
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("failed to get instance principal configuration provider: %w", err))
}
} else { // c.UseResourcePrincipals
c.configProvider, err = ociauth.ResourcePrincipalConfigurationProvider()
if err != nil {
// Surface the error if we can't get a config provider.
// This typically happens when the required environment variables are not set.
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("failed to get resource principal configuration provider: %w", err))
}
}
}
tenancyOCID, err = c.configProvider.TenancyOCID()
if err != nil {
return err
// If configProvider is still nil due to an error, we can't proceed with TenancyOCID()
if c.configProvider != nil {
tenancyOCID, err = c.configProvider.TenancyOCID()
if err != nil {
// It's possible that TenancyOCID() fails even if the provider was created (e.g. permissions)
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("failed to get tenancy OCID from provider: %w", err))
}
}

} else {
// Determine where the SDK config is located
if c.AccessCfgFile == "" {
Expand Down
2 changes: 2 additions & 0 deletions builder/oci/config.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions builder/oci/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,49 @@ func TestConfig(t *testing.T) {
})
}

// Test cases for use_resource_principals
for _, k := range invalidKeys {
t.Run(k+"_mixed_with_use_resource_principals", func(t *testing.T) {
raw := testConfig(cfgFile)
raw["use_resource_principals"] = "true"
raw[k] = "some_random_value"

var c Config
// We need to mock the config provider for resource principals as well,
// similar to how it's done for instance principals.
// Assuming a similar mock exists or can be created: resourcePrincipalConfigurationProviderMock
c.configProvider = instancePrincipalConfigurationProviderMock{} // Or a new mock for resource principals

errs := c.Prepare(raw)

if errs == nil {
t.Fatalf("Expected error when %s is mixed with use_resource_principals, but got none", k)
}
if !strings.Contains(errs.Error(), k) {
t.Errorf("Expected error message for %s to contain '%s', but got: %s", k, k, errs.Error())
}
})
}

t.Run("use_instance_principals_and_use_resource_principals_both_true", func(t *testing.T) {
raw := testConfig(cfgFile)
raw["use_instance_principals"] = "true"
raw["use_resource_principals"] = "true"

var c Config
c.configProvider = instancePrincipalConfigurationProviderMock{} // Mock provider

errs := c.Prepare(raw)

if errs == nil {
t.Fatal("Expected error when both use_instance_principals and use_resource_principals are true, but got none")
}
expectedErrorMsg := "use_instance_principals and use_resource_principals cannot both be true"
if !strings.Contains(errs.Error(), expectedErrorMsg) {
t.Errorf("Expected error message to contain '%s', but got: %s", expectedErrorMsg, errs.Error())
}
})

t.Run("InstanceOptionsAreLegacyImdsEndpointsDisabledTrue", func(t *testing.T) {
raw := testConfig(cfgFile)
raw["instance_options_are_legacy_imds_endpoints_disabled"] = true
Expand Down
5 changes: 4 additions & 1 deletion docs/builders/oci.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,12 @@ based on which authentication method is used.
Principals](https://docs.cloud.oracle.com/en-us/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm)
instead of User Principals. If this key is set to true, setting any one of the `access_cfg_file`,
`access_cfg_file_account`, `region`, `tenancy_ocid`, `user_ocid`, `key_file`, `fingerprint`,
`pass_phrase` parameters will cause an invalid configuration error.
`pass_phrase`, or `use_resource_principals` parameters will cause an invalid configuration error.
Defaults to `false`.

- `use_resource_principals` (boolean) - (Optional) Use Resource Principals for authentication. Resource Principals is a capability in Oracle Cloud Infrastructure Identity and Access Management (IAM) that allows resources (such as Functions, Data Flow applications, and API Gateways) to make service calls to other OCI services. This attribute is mutually exclusive with `access_cfg_file`, `access_cfg_file_account`, `user_ocid`, `tenancy_ocid`, `region`, `fingerprint`, `key_file`, `pass_phrase`, and `use_instance_principals`. Defaults to `false`.
To use resource principals, the resource running Packer (e.g., a Compute instance, a Function) must be part of a [Dynamic Group](https://docs.oracle.com/en-us/iaas/Content/Identity/Tasks/managingdynamicgroups.htm) that has appropriate [Policies](https://docs.oracle.com/en-us/iaas/Content/Identity/Concepts/policygetstarted.htm) granting it permissions to manage resources (e.g., launch instances, create images).

- `access_cfg_file` (string) - The path to the [OCI config
file](https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/sdkconfig.htm).
This parameter is _optional_ when using token-based authentication.
Expand Down
13 changes: 13 additions & 0 deletions example/oci_resource_principals.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"builders":[{
"use_resource_principals": "true",
"availability_domain": "aaaa:PHX-AD-1",
"base_image_ocid": "ocid1.image.oc1.phx.aaaaaaaa5yu6pw3riqtuhxzov7fdngi4tsteganmao54nq3pyxu3hxcuzmoa",
"compartment_ocid": "ocid1.compartment.oc1..aaa",
"image_name": "ResourcePrincipalExampleImage",
"shape": "VM.Standard2.1",
"ssh_username": "opc",
"subnet_ocid": "ocid1.subnet.oc1..aaa",
"type": "oracle-oci"
}]
}
17 changes: 17 additions & 0 deletions example/oci_resource_principals.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0

source "oracle-oci" "resource_principal_example" {
availability_domain = "aaaa:PHX-AD-1"
base_image_ocid = "ocid1.image.oc1.phx.aaaaaaaa5yu6pw3riqtuhxzov7fdngi4tsteganmao54nq3pyxu3hxcuzmoa"
compartment_ocid = "ocid1.compartment.oc1..aaa"
image_name = "ResourcePrincipalExampleImage"
shape = "VM.Standard2.1"
subnet_ocid = "ocid1.subnet.oc1..aaa"
use_resource_principals = "true"
ssh_username = "opc"
}

build {
sources = ["source.oracle-oci.resource_principal_example"]
}
Loading