Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0658fe4
small change to trigger tests
lantoli Oct 1, 2025
bcb6cdb
don't use migration tests
lantoli Oct 1, 2025
425a8b0
rename credentials files to aws_credentials
lantoli Oct 2, 2025
be7f9a6
refactor NewClient and create Credentials
lantoli Oct 2, 2025
af627fe
remove ctx param from NewClient
lantoli Oct 3, 2025
1800c31
keep only role_arn in assume_role
lantoli Oct 3, 2025
8f796cc
fix TestAccServiceAccount_basic
lantoli Oct 3, 2025
ccfca8a
TEMPORARY delete credentials from unit tests init
lantoli Oct 3, 2025
9d778df
dummy credentials in mocked unit tests
lantoli Oct 3, 2025
2420ece
TestPlanChecksClusterTwoRepSpecsWithAutoScalingAndSpecs only in unit …
lantoli Oct 3, 2025
0aa6126
Revert "dummy credentials in mocked unit tests"
lantoli Oct 3, 2025
7770785
rename token env var to MONGODB_ATLAS_ACCESS_TOKEN
lantoli Oct 3, 2025
b61df5b
Reapply "dummy credentials in mocked unit tests"
lantoli Oct 3, 2025
e5c73bf
Revert "TestPlanChecksClusterTwoRepSpecsWithAutoScalingAndSpecs only …
lantoli Oct 3, 2025
e9c477e
revert changes to acc test runner config
lantoli Oct 3, 2025
eeb1d5f
revert init changes
lantoli Oct 3, 2025
809eb87
Merge branch 'CLOUDP-334161-service-accounts-dev' into CLOUDP-345764_…
lantoli Oct 3, 2025
d060712
revert dummy credentials in mocked tests
lantoli Oct 3, 2025
178b4b5
initial AWS code
lantoli Oct 3, 2025
1257c5d
use env vars
lantoli Oct 4, 2025
f63dcf3
remove CredentialProvider
lantoli Oct 4, 2025
d700653
refactor AWS and Provider credentials
lantoli Oct 4, 2025
9193eb2
gov
lantoli Oct 4, 2025
61b62c5
configClient
lantoli Oct 4, 2025
104fb25
refactor Realm client
lantoli Oct 5, 2025
8b2415f
remove Atlas version 220240805
lantoli Oct 5, 2025
0dc3ab4
Revert "remove Atlas version 220240805"
lantoli Oct 5, 2025
b7e555b
use same credentials struct in AWS Secrets Manager
lantoli Oct 5, 2025
c818683
method pick logic
lantoli Oct 5, 2025
2cd7c13
config.GetCredentials
lantoli Oct 5, 2025
7c56a75
warnings
lantoli Oct 5, 2025
35353d3
unit tests
lantoli Oct 5, 2025
2afb3a3
fix linter
lantoli Oct 5, 2025
e37facc
don't log warnings in SDKv2 provider
lantoli Oct 6, 2025
f837b8e
remove todo comments
lantoli Oct 6, 2025
9e2ce3a
Update internal/config/credentials.go
lantoli Oct 6, 2025
c1153b5
Update internal/config/client.go
lantoli Oct 6, 2025
f4bb882
no need to get the credentials
lantoli Oct 6, 2025
5b7ba2a
fix if assume_role is defined but role_arn is not
lantoli Oct 6, 2025
5f2c411
remove unused ctx param
lantoli Oct 6, 2025
25c351f
changelog
lantoli Oct 6, 2025
6df44c7
Update .changelog/3738.txt
lantoli Oct 6, 2025
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
307 changes: 121 additions & 186 deletions internal/config/client.go

Large diffs are not rendered by default.

185 changes: 185 additions & 0 deletions internal/config/credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package config

import (
"os"

"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion"
)

// Credentials has all the authentication fields, it also matches with fields that can be stored in AWS Secrets Manager.
type Credentials struct {
AccessToken string `json:"access_token"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
PublicKey string `json:"public_key"`
PrivateKey string `json:"private_key"`
BaseURL string `json:"base_url"`
RealmBaseURL string `json:"realm_base_url"`
}

// GetCredentials follows the order of AWS Secrets Manager, provider vars and env vars.
func GetCredentials(providerVars, envVars *Vars, getAWSCredentials func(*AWSVars) (*Credentials, error)) (*Credentials, error) {
if awsVars := CoalesceAWSVars(providerVars.GetAWS(), envVars.GetAWS()); awsVars != nil {
awsCredentials, err := getAWSCredentials(awsVars)
if err != nil {
return nil, err
}
return awsCredentials, nil
}
if c := CoalesceCredentials(providerVars.GetCredentials(), envVars.GetCredentials()); c != nil {
return c, nil
}
Comment on lines +22 to +31
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very clear and easy to follow 💯

return &Credentials{}, nil
}

// AuthMethod follows the order of token, SA and PAK.
func (c *Credentials) AuthMethod() AuthMethod {
switch {
case c.HasAccessToken():
return AccessToken
case c.HasServiceAccount():
return ServiceAccount
case c.HasDigest():
return Digest
default:
return Unknown
}
}

func (c *Credentials) HasAccessToken() bool {
return c.AccessToken != ""
}

func (c *Credentials) HasServiceAccount() bool {
return c.ClientID != "" || c.ClientSecret != ""
}

func (c *Credentials) HasDigest() bool {
return c.PublicKey != "" || c.PrivateKey != ""
}

func (c *Credentials) IsPresent() bool {
return c.AuthMethod() != Unknown
}

func (c *Credentials) Warnings() string {
if !c.IsPresent() {
return "No credentials set"
}
// Prefer specific checks over generaric code as there are few combinations and code is clearer.
if c.HasAccessToken() && c.HasServiceAccount() && c.HasDigest() {
return "Access Token will be used although Service Account and API Keys are also set"
}
if c.HasAccessToken() && c.HasServiceAccount() {
return "Access Token will be used although Service Account is also set"
}
if c.HasAccessToken() && c.HasDigest() {
return "Access Token will be used although API Keys is also set"
}
if c.HasServiceAccount() && c.HasDigest() {
return "Service Account will be used although API Keys is also set"
}
return ""
}

type AWSVars struct {
AssumeRoleARN string
SecretName string
Region string
AccessKeyID string
SecretAccessKey string
SessionToken string
Endpoint string
}

func (a *AWSVars) IsPresent() bool {
return a.AssumeRoleARN != ""
}

type Vars struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe rename this to a more meaningful name? providerVars maybe?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vars can be created from provider or environment variables using:

func NewEnvVars() *Vars  # Create Vars from environment variables
getProviderVars     # Create Vars from TFP provider
getSDKv2ProviderVars # Create Vars from SDKv2 provider 

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as I see it all these are provider vars, but can be inputed as provider inputs or env vars, so an option could be to have NewProviderEnvVars, getProviderInputsVars and getSDKv2ProviderInputsVars and change Vars name to ProviderVars. Feel free to ignore if to convinced, this is a nit on naming 😅

Copy link
Member Author

@lantoli lantoli Oct 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think i understand the confusion, you call "provider inputs" when i say "provider". You're right that at the end of the day everything is about the provider :-)

"provider" var means defined in the Terraform provider config, e.g.:

provider "mongodbatlas" {
  client_id     = "my_id"
  client_secret = "my_pass"
}

and Vars can be obtained from the provider config or environment variables, credentials decision order is done here:

if c := CoalesceCredentials(providerVars.GetCredentials(), envVars.GetCredentials()); c != nil { ...

AccessToken string
ClientID string
ClientSecret string
PublicKey string
PrivateKey string
BaseURL string
RealmBaseURL string
AWSAssumeRoleARN string
AWSSecretName string
AWSRegion string
AWSAccessKeyID string
AWSSecretAccessKey string
AWSSessionToken string
AWSEndpoint string
}

func NewEnvVars() *Vars {
return &Vars{
AccessToken: getEnv("MONGODB_ATLAS_ACCESS_TOKEN", "TF_VAR_ACCESS_TOKEN"),
ClientID: getEnv("MONGODB_ATLAS_CLIENT_ID", "TF_VAR_CLIENT_ID"),
ClientSecret: getEnv("MONGODB_ATLAS_CLIENT_SECRET", "TF_VAR_CLIENT_SECRET"),
PublicKey: getEnv("MONGODB_ATLAS_PUBLIC_API_KEY", "MONGODB_ATLAS_PUBLIC_KEY", "MCLI_PUBLIC_API_KEY"),
PrivateKey: getEnv("MONGODB_ATLAS_PRIVATE_API_KEY", "MONGODB_ATLAS_PRIVATE_KEY", "MCLI_PRIVATE_API_KEY"),
BaseURL: getEnv("MONGODB_ATLAS_BASE_URL", "MCLI_OPS_MANAGER_URL"),
RealmBaseURL: getEnv("MONGODB_REALM_BASE_URL"),
AWSAssumeRoleARN: getEnv("ASSUME_ROLE_ARN", "TF_VAR_ASSUME_ROLE_ARN"),
AWSSecretName: getEnv("SECRET_NAME", "TF_VAR_SECRET_NAME"),
AWSRegion: getEnv("AWS_REGION", "TF_VAR_AWS_REGION"),
AWSAccessKeyID: getEnv("AWS_ACCESS_KEY_ID", "TF_VAR_AWS_ACCESS_KEY_ID"),
AWSSecretAccessKey: getEnv("AWS_SECRET_ACCESS_KEY", "TF_VAR_AWS_SECRET_ACCESS_KEY"),
AWSSessionToken: getEnv("AWS_SESSION_TOKEN", "TF_VAR_AWS_SESSION_TOKEN"),
AWSEndpoint: getEnv("STS_ENDPOINT", "TF_VAR_STS_ENDPOINT"),
}
}

func (e *Vars) GetCredentials() *Credentials {
return &Credentials{
AccessToken: e.AccessToken,
ClientID: e.ClientID,
ClientSecret: e.ClientSecret,
PublicKey: e.PublicKey,
PrivateKey: e.PrivateKey,
BaseURL: e.BaseURL,
RealmBaseURL: e.RealmBaseURL,
}
}

// GetAWS returns variables in the format AWS expects, e.g. region in lowercase.
func (e *Vars) GetAWS() *AWSVars {
return &AWSVars{
AssumeRoleARN: e.AWSAssumeRoleARN,
SecretName: e.AWSSecretName,
Region: conversion.MongoDBRegionToAWSRegion(e.AWSRegion),
AccessKeyID: e.AWSAccessKeyID,
SecretAccessKey: e.AWSSecretAccessKey,
SessionToken: e.AWSSessionToken,
Endpoint: e.AWSEndpoint,
}
}

func getEnv(key ...string) string {
for _, k := range key {
if v := os.Getenv(k); v != "" {
return v
}
}
return ""
}

func CoalesceAWSVars(awsVars ...*AWSVars) *AWSVars {
for _, awsVar := range awsVars {
if awsVar.IsPresent() {
return awsVar
}
}
return nil
}

func CoalesceCredentials(credentials ...*Credentials) *Credentials {
for _, credential := range credentials {
if credential.IsPresent() {
return credential
}
}
return nil
}
Loading