Skip to content

Commit 5cdcc11

Browse files
feat: Add Stream PrivateLink Endpoint (#1547)
Co-authored-by: Rakhul S Prakash <rakhul.s.prakash@peerislands.io>
1 parent 25561c5 commit 5cdcc11

31 files changed

Lines changed: 1994 additions & 1 deletion

.github/workflows/contract-testing.yaml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ jobs:
3535
search-index: ${{ steps.filter.outputs.search-index }}
3636
stream-connection: ${{ steps.filter.outputs.stream-connection }}
3737
stream-instance: ${{ steps.filter.outputs.stream-instance }}
38+
stream-privatelink-endpoint: ${{ steps.filter.outputs.stream-privatelink-endpoint }}
3839
stream-processor: ${{ steps.filter.outputs.stream-processor }}
3940
stream-workspace: ${{ steps.filter.outputs.stream-workspace }}
4041
third-party-integration: ${{ steps.filter.outputs.third-party-integration }}
@@ -93,6 +94,8 @@ jobs:
9394
- 'cfn-resources/stream-connection/**'
9495
stream-instance:
9596
- 'cfn-resources/stream-instance/**'
97+
stream-privatelink-endpoint:
98+
- 'cfn-resources/stream-privatelink-endpoint/**'
9699
stream-processor:
97100
- 'cfn-resources/stream-processor/**'
98101
stream-workspace:
@@ -1081,6 +1084,46 @@ jobs:
10811084
pushd cfn-resources/stream-instance
10821085
make create-test-resources
10831086
cat inputs/inputs_1_create.json
1087+
make run-contract-testing
1088+
make delete-test-resources
1089+
stream-privatelink-endpoint:
1090+
needs: change-detection
1091+
if: ${{ needs.change-detection.outputs.stream-privatelink-endpoint == 'true' }}
1092+
runs-on: ubuntu-latest
1093+
steps:
1094+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
1095+
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5
1096+
with:
1097+
go-version-file: 'cfn-resources/go.mod'
1098+
- name: setup Atlas CLI
1099+
uses: mongodb/atlas-github-action@e3c9e0204659bafbb3b65e1eb1ee745cca0e9f3b
1100+
- uses: aws-actions/setup-sam@c2a20b1822cc4a6bc594ff7f1dbb658758e383c3
1101+
with:
1102+
use-installer: true
1103+
- uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708
1104+
with:
1105+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_TEST_ENV }}
1106+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_TEST_ENV }}
1107+
aws-region: eu-west-1
1108+
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
1109+
with:
1110+
python-version: '3.9'
1111+
cache: 'pip' # caching pip dependencies
1112+
- run: pip install cloudformation-cli cloudformation-cli-go-plugin
1113+
- name: Run the Contract test
1114+
shell: bash
1115+
env:
1116+
MONGODB_ATLAS_PUBLIC_API_KEY: ${{ secrets.CLOUD_DEV_PUBLIC_KEY }}
1117+
MONGODB_ATLAS_PRIVATE_API_KEY: ${{ secrets.CLOUD_DEV_PRIVATE_KEY }}
1118+
MONGODB_ATLAS_ORG_ID: ${{ secrets.CLOUD_DEV_ORG_ID }}
1119+
MONGODB_ATLAS_OPS_MANAGER_URL: ${{ vars.MONGODB_ATLAS_BASE_URL }}
1120+
MONGODB_ATLAS_PROFILE: cfn-cloud-dev-github-action
1121+
run: |
1122+
pushd cfn-resources/stream-privatelink-endpoint
1123+
make create-test-resources
1124+
1125+
cat inputs/*
1126+
10841127
make run-contract-testing
10851128
make delete-test-resources
10861129
stream-processor:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"artifact_type": "RESOURCE",
3+
"typeName": "MongoDB::Atlas::StreamPrivatelinkEndpoint",
4+
"language": "go",
5+
"runtime": "provided.al2",
6+
"entrypoint": "bootstrap",
7+
"testEntrypoint": "bootstrap",
8+
"settings": {
9+
"version": false,
10+
"subparser_name": null,
11+
"verbose": 0,
12+
"force": false,
13+
"type_name": null,
14+
"artifact_type": null,
15+
"endpoint_url": null,
16+
"region": null,
17+
"target_schemas": [],
18+
"profile": null,
19+
"import_path": "github.com/mongodb/mongodbatlas-cloudformation-resources/stream-privatelink-endpoint",
20+
"protocolVersion": "2.0.0"
21+
},
22+
"canarySettings": {
23+
"contract_test_file_names": [
24+
"inputs_1.json"
25+
]
26+
}
27+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
.PHONY: build debug clean create-test-resources delete-test-resources run-contract-testing
2+
tags=logging callback metrics scheduler
3+
cgo=0
4+
goos=linux
5+
goarch=amd64
6+
CFNREP_GIT_SHA?=$(shell git rev-parse HEAD)
7+
ldXflags=-s -w -X github.com/mongodb/mongodbatlas-cloudformation-resources/util.defaultLogLevel=info -X github.com/mongodb/mongodbatlas-cloudformation-resources/version.Version=${CFNREP_GIT_SHA}
8+
ldXflagsD=-X github.com/mongodb/mongodbatlas-cloudformation-resources/util.defaultLogLevel=debug -X github.com/mongodb/mongodbatlas-cloudformation-resources/version.Version=${CFNREP_GIT_SHA}
9+
10+
build:
11+
cfn generate
12+
env GOOS=$(goos) CGO_ENABLED=$(cgo) GOARCH=$(goarch) go build -ldflags="$(ldXflags)" -tags="$(tags)" -o bin/bootstrap cmd/main.go
13+
14+
debug:
15+
cfn generate
16+
env GOOS=$(goos) CGO_ENABLED=$(cgo) GOARCH=$(goarch) go build -ldflags="$(ldXflagsD)" -tags="$(tags)" -o bin/debug cmd/main.go
17+
18+
clean:
19+
rm -rf bin
20+
21+
submit: clean build
22+
@echo "==> Submitting to private registry for testing"
23+
cfn submit --set-default --region us-east-1
24+
25+
create-test-resources:
26+
@echo "==> Creating test files and resources for contract testing"
27+
./test/contract-testing/cfn-test-create.sh
28+
29+
delete-test-resources:
30+
@echo "==> Delete test resources used for contract testing"
31+
./test/contract-testing/cfn-test-delete.sh
32+
33+
run-contract-testing:
34+
@echo "==> Run contract testing"
35+
make build
36+
sam local start-lambda &
37+
cfn test --function-name TestEntrypoint --verbose
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# MongoDB::Atlas::StreamPrivatelinkEndpoint
2+
3+
## Description
4+
5+
Resource for creating and managing [Stream Processing Private Link Endpoints](https://www.mongodb.com/docs/api/doc/atlas-admin-api-v2/operation/operation-createprivatelinkconnection). This resource enables secure, private connectivity between Atlas Stream Processing and streaming services (AWS MSK, Confluent Cloud, or AWS S3) over AWS PrivateLink. This resource supports AWS only.
6+
7+
## Requirements
8+
9+
Set up an AWS profile to securely give CloudFormation access to your Atlas credentials.
10+
For instructions on setting up a profile, [see here](/README.md#mongodb-atlas-api-keys-credential-management).
11+
12+
## Attributes and Parameters
13+
14+
See the [resource docs](docs/README.md). Also refer [AWS security best practices for CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/security-best-practices.html#creds) to manage credentials.
15+
16+
## CloudFormation Examples
17+
18+
See the example [CFN Template](/examples/atlas-streams/stream-privatelink-endpoint/stream-privatelink-endpoint-s3.json) for example resource.
19+
20+
## Deployment
21+
22+
### Prerequisites
23+
24+
- **Atlas Project**: You must have an existing MongoDB Atlas project.
25+
- **AWS Account**: An AWS account with appropriate permissions for PrivateLink and VPC endpoint creation.
26+
- **Atlas Credentials**: Set up an AWS profile to securely give CloudFormation access to your Atlas credentials. For instructions, see [MongoDB Atlas API Keys Credential Management](/README.md#mongodb-atlas-api-keys-credential-management).
27+
- **AWS Credentials**: Configure AWS credentials with permissions to create VPC endpoints and manage PrivateLink connections.
28+
29+
### Basic Deployment
30+
31+
```bash
32+
aws cloudformation deploy \
33+
--template-file examples/atlas-streams/stream-privatelink-endpoint/stream-privatelink-endpoint-s3.json \
34+
--stack-name atlas-stream-privatelink-endpoint-s3 \
35+
--parameter-overrides \
36+
ProjectId=<YOUR_PROJECT_ID> \
37+
Region=eu-west-1 \
38+
ServiceEndpointId=com.amazonaws.eu-west-1.s3 \
39+
Profile=default \
40+
--capabilities CAPABILITY_IAM \
41+
--region eu-west-1
42+
```
43+
44+
## Verification
45+
46+
### Using Atlas CLI
47+
48+
After deployment, verify the Private Link Endpoint was created:
49+
50+
```bash
51+
# List all Private Link Endpoints for the project
52+
atlas streams privatelink list --projectId <PROJECT_ID>
53+
54+
# Describe a specific Private Link Endpoint
55+
atlas streams privatelink describe <ENDPOINT_ID> --projectId <PROJECT_ID>
56+
```
57+
58+
### Using Atlas UI
59+
60+
1. Navigate to your Atlas project
61+
2. Go to **Network Access****Stream Processing Private Link Endpoints**
62+
3. Verify the endpoint appears with:
63+
- Vendor type: "S3", "MSK", or "CONFLUENT"
64+
- State: "AVAILABLE" (may take a few minutes to transition)
65+
- Correct region and service endpoint ID

cfn-resources/stream-privatelink-endpoint/cmd/main.go

Lines changed: 85 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright 2026 MongoDB Inc
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package resource
16+
17+
import (
18+
"context"
19+
20+
"go.mongodb.org/atlas-sdk/v20250312013/admin"
21+
22+
"github.com/aws-cloudformation/cloudformation-cli-go-plugin/cfn/handler"
23+
24+
"github.com/mongodb/mongodbatlas-cloudformation-resources/util"
25+
"github.com/mongodb/mongodbatlas-cloudformation-resources/util/constants"
26+
)
27+
28+
const (
29+
stateDone = "DONE"
30+
stateFailed = "FAILED"
31+
stateDeleteRequested = "DELETE_REQUESTED"
32+
stateDeleting = "DELETING"
33+
stateDeleted = "DELETED"
34+
35+
callbackDelaySeconds = 3
36+
callbackKey = "callbackStreamPrivatelinkEndpoint"
37+
)
38+
39+
var callbackContext = map[string]any{callbackKey: true}
40+
41+
func isCallback(req *handler.Request) bool {
42+
_, found := req.CallbackContext[callbackKey]
43+
return found
44+
}
45+
46+
func validateProgress(client *util.MongoDBClient, model *Model, isDelete bool) handler.ProgressEvent {
47+
ctx := context.Background()
48+
projectID := util.SafeString(model.ProjectId)
49+
connectionID := util.SafeString(model.Id)
50+
51+
streamsPrivateLinkConnection, apiResp, err := client.AtlasSDK.StreamsApi.GetPrivateLinkConnection(ctx, projectID, connectionID).Execute()
52+
notFound := util.StatusNotFound(apiResp)
53+
54+
if err != nil && !notFound {
55+
return handleError(apiResp, constants.READ, err)
56+
}
57+
58+
state := stateDeleted
59+
if streamsPrivateLinkConnection != nil {
60+
state = streamsPrivateLinkConnection.GetState()
61+
}
62+
63+
targetState := stateDone
64+
if isDelete {
65+
targetState = stateDeleted
66+
}
67+
68+
if state == stateFailed {
69+
return handleFailedState(streamsPrivateLinkConnection)
70+
}
71+
72+
if state != targetState {
73+
return inProgressEvent(model, streamsPrivateLinkConnection)
74+
}
75+
76+
if isDelete {
77+
return handler.ProgressEvent{
78+
OperationStatus: handler.Success,
79+
Message: constants.Complete,
80+
}
81+
}
82+
83+
UpdateModel(model, streamsPrivateLinkConnection)
84+
return handler.ProgressEvent{
85+
OperationStatus: handler.Success,
86+
Message: constants.Complete,
87+
ResourceModel: model,
88+
}
89+
}
90+
91+
func inProgressEvent(model *Model, apiResp *admin.StreamsPrivateLinkConnection) handler.ProgressEvent {
92+
UpdateModel(model, apiResp)
93+
return handler.ProgressEvent{
94+
OperationStatus: handler.InProgress,
95+
Message: constants.Pending,
96+
ResourceModel: model,
97+
CallbackDelaySeconds: callbackDelaySeconds,
98+
CallbackContext: callbackContext,
99+
}
100+
}

0 commit comments

Comments
 (0)