Skip to content
Merged
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
43 changes: 43 additions & 0 deletions .github/workflows/contract-testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
backup-compliance-policy: ${{ steps.filter.outputs.backup-compliance-policy }}
cloud-backup-restore-jobs: ${{ steps.filter.outputs.cloud-backup-restore-jobs }}
cluster-outage-simulation: ${{ steps.filter.outputs.cluster-outage-simulation }}
database-user: ${{ steps.filter.outputs.database-user }}
federated-database-instance: ${{ steps.filter.outputs.federated-database-instance }}
federated-query-limit: ${{ steps.filter.outputs.federated-query-limit }}
federated-settings-identity-provider: ${{ steps.filter.outputs.federated-settings-identity-provider }}
Expand Down Expand Up @@ -56,6 +57,8 @@ jobs:
- 'cfn-resources/cloud-backup-restore-jobs/**'
cluster-outage-simulation:
- 'cfn-resources/cluster-outage-simulation/**'
database-user:
- 'cfn-resources/database-user/**'
federated-database-instance:
- 'cfn-resources/federated-database-instance/**'
federated-query-limit:
Expand Down Expand Up @@ -373,6 +376,46 @@ jobs:

cat inputs/inputs_1_create.json

make run-contract-testing
make delete-test-resources
database-user:
needs: change-detection
if: ${{ needs.change-detection.outputs.database-user == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5
with:
go-version-file: 'cfn-resources/go.mod'
- name: setup Atlas CLI
uses: mongodb/atlas-github-action@e3c9e0204659bafbb3b65e1eb1ee745cca0e9f3b
- uses: aws-actions/setup-sam@c2a20b1822cc4a6bc594ff7f1dbb658758e383c3
with:
use-installer: true
- uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_TEST_ENV }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_TEST_ENV }}
aws-region: eu-west-1
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
with:
python-version: '3.9'
cache: 'pip' # caching pip dependencies
- run: pip install cloudformation-cli cloudformation-cli-go-plugin
- name: Run the Contract test
shell: bash
env:
MONGODB_ATLAS_PUBLIC_API_KEY: ${{ secrets.CLOUD_DEV_PUBLIC_KEY }}
MONGODB_ATLAS_PRIVATE_API_KEY: ${{ secrets.CLOUD_DEV_PRIVATE_KEY }}
MONGODB_ATLAS_ORG_ID: ${{ secrets.CLOUD_DEV_ORG_ID }}
MONGODB_ATLAS_OPS_MANAGER_URL: ${{ vars.MONGODB_ATLAS_BASE_URL }}
MONGODB_ATLAS_PROFILE: cfn-cloud-dev-github-action
run: |
pushd cfn-resources/database-user
make create-test-resources

cat inputs/*

make run-contract-testing
make delete-test-resources
federated-database-instance:
Expand Down
20 changes: 19 additions & 1 deletion cfn-resources/database-user/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,25 @@ build:

debug:
cfn generate
env GOOS=$(goos) CGO_ENABLED=$(cgo) GOARCH=$(goarch) go build -ldflags="$(ldXflagsD)" -tags="$(tags)" -o bin/bootstrap cmd/main.go
env GOOS=$(goos) CGO_ENABLED=$(cgo) GOARCH=$(goarch) go build -ldflags="$(ldXflagsD)" -tags="$(tags)" -o bin/debug cmd/main.go

clean:
rm -rf bin

submit: clean build # submit to private registry must use release build not debug build
@echo "==> Submitting to private registry for testing"
cfn submit --set-default --region us-east-1

create-test-resources:
@echo "==> Creating test files and resources for contract testing"
./test/contract-testing/cfn-test-create.sh

delete-test-resources:
@echo "==> Delete test resources used for contract testing"
./test/contract-testing/cfn-test-delete.sh

run-contract-testing:
@echo "==> Run contract testing"
make build
sam local start-lambda &
cfn test --function-name TestEntrypoint --verbose
1 change: 1 addition & 0 deletions cfn-resources/database-user/cmd/resource/model.go

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

11 changes: 9 additions & 2 deletions cfn-resources/database-user/cmd/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ func Read(req handler.Request, prevModel *Model, currentModel *Model) (handler.P
currentModel.LdapAuthType = databaseUser.LdapAuthType
currentModel.AWSIAMType = databaseUser.AwsIAMType
currentModel.X509Type = databaseUser.X509Type
currentModel.OIDCAuthType = databaseUser.OidcAuthType
currentModel.Username = &databaseUser.Username
var roles []RoleDefinition

Expand Down Expand Up @@ -252,7 +253,9 @@ func List(req handler.Request, prevModel *Model, currentModel *Model) (handler.P
DatabaseName: &databaseUser.DatabaseName,
Description: databaseUser.Description,
LdapAuthType: databaseUser.LdapAuthType,
AWSIAMType: databaseUser.AwsIAMType,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

good catch!

X509Type: databaseUser.X509Type,
OIDCAuthType: databaseUser.OidcAuthType,
Username: &databaseUser.Username,
ProjectId: currentModel.ProjectId,
}
Expand Down Expand Up @@ -341,10 +344,13 @@ func setModel(currentModel *Model) (*admin.CloudDatabaseUser, error) {
if currentModel.X509Type == nil {
currentModel.X509Type = &none
}
if currentModel.OIDCAuthType == nil {
currentModel.OIDCAuthType = &none
}

if currentModel.Password == nil {
if (*currentModel.LdapAuthType == none) && (*currentModel.AWSIAMType == none) && (*currentModel.X509Type == none) {
err := fmt.Errorf("password cannot be empty if not LDAP or IAM or X509 is not provided")
if (*currentModel.LdapAuthType == none) && (*currentModel.AWSIAMType == none) && (*currentModel.X509Type == none) && (*currentModel.OIDCAuthType == none) {
err := fmt.Errorf("password cannot be empty if not LDAP or IAM or X509 or OIDC is not provided")
return nil, err
}
currentModel.Password = aws.String("")
Expand All @@ -364,6 +370,7 @@ func setModel(currentModel *Model) (*admin.CloudDatabaseUser, error) {
LdapAuthType: currentModel.LdapAuthType,
AwsIAMType: currentModel.AWSIAMType,
X509Type: currentModel.X509Type,
OidcAuthType: currentModel.OIDCAuthType,
DeleteAfterDate: util.StringPtrToTimePtr(currentModel.DeleteAfterDate),
Description: currentModel.Description,
}
Expand Down
14 changes: 14 additions & 0 deletions cfn-resources/database-user/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ To declare this entity in your AWS CloudFormation template, use the following sy
"<a href="#labels" title="Labels">Labels</a>" : <i>[ <a href="labeldefinition.md">labelDefinition</a>, ... ]</i>,
"<a href="#ldapauthtype" title="LdapAuthType">LdapAuthType</a>" : <i>String</i>,
"<a href="#x509type" title="X509Type">X509Type</a>" : <i>String</i>,
"<a href="#oidcauthtype" title="OIDCAuthType">OIDCAuthType</a>" : <i>String</i>,
"<a href="#password" title="Password">Password</a>" : <i>String</i>,
"<a href="#projectid" title="ProjectId">ProjectId</a>" : <i>String</i>,
"<a href="#roles" title="Roles">Roles</a>" : <i>[ <a href="roledefinition.md">roleDefinition</a>, ... ]</i>,
Expand All @@ -42,6 +43,7 @@ Properties:
- <a href="labeldefinition.md">labelDefinition</a></i>
<a href="#ldapauthtype" title="LdapAuthType">LdapAuthType</a>: <i>String</i>
<a href="#x509type" title="X509Type">X509Type</a>: <i>String</i>
<a href="#oidcauthtype" title="OIDCAuthType">OIDCAuthType</a>: <i>String</i>
<a href="#password" title="Password">Password</a>: <i>String</i>
<a href="#projectid" title="ProjectId">ProjectId</a>: <i>String</i>
<a href="#roles" title="Roles">Roles</a>: <i>
Expand Down Expand Up @@ -130,6 +132,18 @@ _Allowed Values_: <code>NONE</code> | <code>MANAGED</code> | <code>CUSTOMER</cod

_Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)

#### OIDCAuthType

Human-readable label that indicates whether the new database user or group authenticates with OIDC federated authentication. To create a federated authentication user, specify the value of USER in this field. To create a federated authentication group, specify the value of IDP_GROUP in this field. Default value is `NONE`.

_Required_: No

_Type_: String

_Allowed Values_: <code>NONE</code> | <code>USER</code> | <code>IDP_GROUP</code>

_Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt)

#### Password

The user’s password. This field is not included in the entity returned from the server.
Expand Down
5 changes: 5 additions & 0 deletions cfn-resources/database-user/mongodb-atlas-databaseuser.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@
],
"type": "string"
},
"OIDCAuthType": {
"description": "Human-readable label that indicates whether the new database user or group authenticates with OIDC federated authentication. To create a federated authentication user, specify the value of USER in this field. To create a federated authentication group, specify the value of IDP_GROUP in this field. Default value is `NONE`.",
"enum": ["NONE", "USER", "IDP_GROUP"],
"type": "string"
},
"Password": {
"description": "The user’s password. This field is not included in the entity returned from the server.",
"type": "string"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash

# This tool generates the resources and json files in the inputs/ for `cfn test`.
set -o errexit
set -o nounset
set -o pipefail

projectName="cfn-test-bot-$(date +%s)-$RANDOM"

# create project
projectId=$(atlas projects create "${projectName}" --output=json | jq -r '.id')

echo "projectId: $projectId"
echo "projectName: $projectName"

./test/cfn-test-create-inputs.sh "$projectName"
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash

# This tool deletes the mongodb resources used for `cfn test` as inputs.
set -o errexit
set -o nounset
set -o pipefail

projectId=$(jq -r '.ProjectId' ./inputs/inputs_1_create.json)

# delete project
if atlas projects delete "$projectId" --force; then
echo "$projectId project deletion OK"
else
(echo "Failed cleaning project: $projectId" && exit 1)
fi
28 changes: 28 additions & 0 deletions cfn-resources/database-user/test/inputs_3_create.template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"Username": "DataUser3",
"Password": "MongoDB12345%",
"ProjectId": "${MONGODB_ATLAS_PROJECT_ID}",
"Profile": "${MONGODB_ATLAS_PROFILE}",
"DatabaseName": "admin",
"Description": "User with Labels to test OIDCAuthType field",
"OIDCAuthType": "NONE",
"Roles": [
{
"RoleName": "readWrite",
"DatabaseName": "testdb",
"CollectionName": "col1"
}
],
"Scopes": [
{
"Type": "CLUSTER",
"Name": "testdb"
}
],
"Labels": [
{
"Key": "testType",
"Value": "oidc-field-validation"
}
]
}
31 changes: 31 additions & 0 deletions cfn-resources/database-user/test/inputs_3_update.template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"Username": "DataUser3",
"Password": "MongoDB12345%",
"ProjectId": "${MONGODB_ATLAS_PROJECT_ID}",
"Profile": "${MONGODB_ATLAS_PROFILE}",
"DatabaseName": "admin",
"Description": "Updated user with modified Labels",
"OIDCAuthType": "NONE",
"Roles": [
{
"RoleName": "readWriteAnyDatabase",
"DatabaseName": "admin"
}
],
"Scopes": [
{
"Type": "CLUSTER",
"Name": "testdb2"
}
],
"Labels": [
{
"Key": "testType",
"Value": "oidc-field-validation"
},
{
"Key": "updated",
"Value": "true"
}
]
}
87 changes: 87 additions & 0 deletions examples/database-user/oidcUser.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "This template creates a database user with OIDC (OpenID Connect) federated authentication. OIDC authentication requires federation settings to be configured in your MongoDB Atlas organization. OIDCAuthType supports USER (individual users) and IDP_GROUP (identity provider groups).",
"Parameters": {
"ProjectId": {
"Type": "String",
"Description": "Unique 24-hexadecimal digit string that identifies your project"
},
"Profile": {
"Type": "String",
"Description": "Secret Manager Profile that contains the Atlas Programmatic keys",
"ConstraintDescription": "",
"Default": "default"
},
"DatabaseName": {
"Type": "String",
"Description": "Database against which the database user authenticates. For OIDC authentication, this must be $external",
"Default": "$external"
},
"Username": {
"Type": "String",
"Description": "Username for OIDC authentication. Format: <federation_settings_id>/<username> (e.g., 6489e4f0bebcb4b0dbd8e7b3/john.doe). The federation_settings_id can be found in your Atlas organization's federation settings."
},
"Description": {
"Type": "String",
"Description": "Description of this database user.",
"Default": "OIDC federated authentication user"
}
},
"Mappings": {},
"Resources": {
"OidcUser": {
"Type": "MongoDB::Atlas::DatabaseUser",
"Metadata": {
"Comment": "Remember to update the \"Roles\" field with a list of roles that you want to assign to the user. OIDC authentication requires federation settings to be configured in your Atlas organization. The username must follow the format: <federation_settings_id>/<username>. For group-based authentication, use OIDCAuthType: IDP_GROUP and format: <federation_settings_id>/<group_name>"
},
"Properties": {
"Username": {
"Ref": "Username"
},
"OIDCAuthType": "USER",
"ProjectId": {
"Ref": "ProjectId"
},
"DatabaseName": {
"Ref": "DatabaseName"
},
"Profile": {
"Ref": "Profile"
},
"Description": {
"Ref": "Description"
},
"Roles": [
{
"RoleName": "readWriteAnyDatabase",
"DatabaseName": "admin"
}
],
"Labels": [
{
"Key": "authType",
"Value": "oidc"
},
{
"Key": "environment",
"Value": "production"
}
]
}
}
},
"Outputs": {
"MongoDBOidcUsername": {
"Description": "Unique identifier for the OIDC database user",
"Value": {
"Fn::GetAtt": ["OidcUser", "UserCFNIdentifier"]
}
},
"Username": {
"Description": "Username of the OIDC database user",
"Value": {
"Ref": "Username"
}
}
}
}
Loading