Skip to content

Commit

Permalink
chore: add mongodb amazon vpc example
Browse files Browse the repository at this point in the history
  • Loading branch information
metaclips committed Apr 5, 2024
1 parent 6060457 commit ea2689e
Show file tree
Hide file tree
Showing 7 changed files with 458 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Amazon VPC

This hands-on example uses Ockam to create an end-to-end encrypted portal to MongoDB.

We connect a nodejs app in one Amazon VPC with a Amazon VPC managed Mongo database in another Amazon VPC.
The example uses AWS CLI to create these VPCs.

You can read a detailed walkthough of this example at:
https://docs.ockam.io/portals/databases/mongodb/amazon_vpc
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const { MongoClient } = require("mongodb");

// Configuration to connect to the MongoDB database on - 127.0.0.1:17017
//
// 127.0.0.1:17017 is the inlet address of the tcp portal to MongoDB.
// This inlet is local to analysis_corp, the MongoDB database is remote in bank_corp.
const uri = "mongodb://127.0.0.1:17017/mydb"

// Attempt to connect to the database in a loop.
//
// Since all the containers may take a few seconds to start up.
// We'll attempt to connect in a loop once every 10 seconds by default.
async function connect(attempts = 100, waitTimeBetweenAttempts = 10000) {
while (attempts--) {
const client = new MongoClient(uri);
try {
await client.connect();
console.log("Connected to the database.\n");
return client;
} catch (err) {
console.log(`Couldn't connect to the database: ${err.message}, retrying ...`);
if (attempts == 0) throw err;
await new Promise((resolve) => setTimeout(resolve, waitTimeBetweenAttempts));
}
}
}

async function run() {
const client = await connect();
try {
const database = client.db('sample');
const users = database.collection('users');

console.log("Inserting some data into the users collections ...");
const docs = ["Alice", "Bob", "Charlie"].map((name) => ({ name: name, score: Math.floor(Math.random() * 101) }));
await users.insertMany(docs);

const result = await users.find().toArray()
console.log("USERS:", result);
console.log(
"\nThe example run was successful 🥳.\n" +
"\nThe app connected with the database through an encrypted portal." +
"\nInserted some data, and querried it back.\n",
);
} finally {
await client.close();
console.log("Disconnected from the database.");
}

}
run()
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/usr/bin/env bash
set -ex

run() {
enrollment_ticket="$1"

# ----------------------------------------------------------------------------------------------------------------
# CREATE NETWORK

# Create a new VPC and tag it.
vpc_id=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --query 'Vpc.VpcId')
aws ec2 create-tags --resources "$vpc_id" --tags "Key=Name,Value=${name}-vpc"

# Create an Internet Gateway and attach it to the VPC.
gw_id=$(aws ec2 create-internet-gateway --query 'InternetGateway.InternetGatewayId')
aws ec2 attach-internet-gateway --vpc-id "$vpc_id" --internet-gateway-id "$gw_id"

# Create a route table and a route to the Internet through the Gateway.
rtb_id=$(aws ec2 create-route-table --vpc-id "$vpc_id" --query 'RouteTable.RouteTableId')
aws ec2 create-route --route-table-id "$rtb_id" --destination-cidr-block 0.0.0.0/0 --gateway-id "$gw_id"

# Create a subnet and associate the route table
az=$(aws ec2 describe-availability-zones --query "AvailabilityZones[0].ZoneName")
subnet_id=$(aws ec2 create-subnet --vpc-id "$vpc_id" --cidr-block 10.0.0.0/25 \
--availability-zone "$az" --query 'Subnet.SubnetId')
aws ec2 modify-subnet-attribute --subnet-id "$subnet_id" --map-public-ip-on-launch
aws ec2 associate-route-table --subnet-id "$subnet_id" --route-table-id "$rtb_id"

# Create a security group to allow:
# - TCP egress to the Internet
# - SSH ingress from the Internet
sg_id=$(aws ec2 create-security-group --group-name "${name}-sg" --vpc-id "$vpc_id" --query 'GroupId' \
--description "Allow TCP egress and Postgres ingress")
aws ec2 authorize-security-group-egress --group-id "$sg_id" --cidr 0.0.0.0/0 --protocol tcp --port 0-65535
aws ec2 authorize-security-group-ingress --group-id "$sg_id" --cidr 0.0.0.0/0 --protocol tcp --port 22

# ----------------------------------------------------------------------------------------------------------------
# CREATE INSTANCE

ami_id=$(aws ec2 describe-images --owners 137112412989 --query "Images | sort_by(@, &CreationDate) | [-1].ImageId" \
--filters "Name=name,Values=al2023-ami-2023*" "Name=architecture,Values=x86_64" \
"Name=virtualization-type,Values=hvm" "Name=root-device-type,Values=ebs" )

aws ec2 create-key-pair --key-name "${name}-key" --query 'KeyMaterial' > key.pem
chmod 400 key.pem

sed "s/\$ENROLLMENT_TICKET/${enrollment_ticket}/g" run_ockam.sh > user_data.sh
instance_id=$(aws ec2 run-instances --image-id "$ami_id" --instance-type c5n.large \
--subnet-id "$subnet_id" --security-group-ids "$sg_id" \
--key-name "${name}-key" --user-data file://user_data.sh --query 'Instances[0].InstanceId')
aws ec2 create-tags --resources "$instance_id" --tags "Key=Name,Value=${name}-ec2-instance"
aws ec2 wait instance-running --instance-ids "$instance_id"
ip=$(aws ec2 describe-instances --instance-ids "$instance_id" --query 'Reservations[0].Instances[0].PublicIpAddress')
rm -f user_data.sh

until scp -o StrictHostKeyChecking=no -i ./key.pem ./app.js "ec2-user@$ip:app.js"; do sleep 10; done
ssh -o StrictHostKeyChecking=no -i ./key.pem "ec2-user@$ip" \
'bash -s' << 'EOS'
sudo yum update -y && sudo yum install nodejs -y
npm install mongodb
node app.js
EOS
}

cleanup() {
# ----------------------------------------------------------------------------------------------------------------
# DELETE INSTANCE

rm -f user_data.sh
instance_ids=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=${name}-ec2-instance" \
--query "Reservations[*].Instances[*].InstanceId")
for i in $instance_ids; do
aws ec2 terminate-instances --instance-ids "$i"
aws ec2 wait instance-terminated --instance-ids "$i"
done

if aws ec2 describe-key-pairs --key-names "${name}-key" &>/dev/null; then
aws ec2 delete-key-pair --key-name "${name}-key"
fi
rm -f key.pem


# ----------------------------------------------------------------------------------------------------------------
# DELETE NETWORK

vpc_ids=$(aws ec2 describe-vpcs --query 'Vpcs[*].VpcId' --filters "Name=tag:Name,Values=${name}-vpc")

for vpc_id in $vpc_ids; do
internet_gateways=$(aws ec2 describe-internet-gateways --query "InternetGateways[*].InternetGatewayId" \
--filters Name=attachment.vpc-id,Values="$vpc_id")
for i in $internet_gateways; do
aws ec2 detach-internet-gateway --internet-gateway-id "$i" --vpc-id "$vpc_id"
aws ec2 delete-internet-gateway --internet-gateway-id "$i"
done

subnet_ids=$(aws ec2 describe-subnets --query "Subnets[*].SubnetId" --filters Name=vpc-id,Values="$vpc_id")
for i in $subnet_ids; do aws ec2 delete-subnet --subnet-id "$i"; done

route_tables=$(aws ec2 describe-route-tables --filters Name=vpc-id,Values="$vpc_id" \
--query 'RouteTables[?length(Associations[?Main!=`true`]) > `0` || length(Associations) == `0`].RouteTableId')
for i in $route_tables; do aws ec2 delete-route-table --route-table-id "$i" || true; done

security_groups=$(aws ec2 describe-security-groups --filters Name=vpc-id,Values="$vpc_id" \
--query "SecurityGroups[?!contains(GroupName, 'default')].[GroupId]")
for i in $security_groups; do aws ec2 delete-security-group --group-id "$i"; done

if aws ec2 describe-vpcs --vpc-ids "$vpc_id" &>/dev/null; then
aws ec2 delete-vpc --vpc-id "$vpc_id"
fi
done
}

export AWS_PAGER="";
export AWS_DEFAULT_OUTPUT="text";

user=""
command -v sha256sum &>/dev/null && user=$(aws sts get-caller-identity | sha256sum | cut -c 1-20)
command -v shasum &>/dev/null && user=$(aws sts get-caller-identity | shasum -a 256 | cut -c 1-20)
export name="ockam-ex-mongo-db-analysis-corp-$user"

# Check if the first argument is "cleanup"
# If it is, call the cleanup function. If not, call the run function.
if [ "$1" = "cleanup" ]; then cleanup; else run "$1"; fi
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/bash
set -ex

# Change into ec2-user's home directory and use sudo to run the commands as ec2-user
cd /home/ec2-user
sudo -u ec2-user bash << 'EOS'
set -ex
# Install Ockam Command
curl --proto '=https' --tlsv1.2 -sSfL https://install.command.ockam.io | bash
source "$HOME/.ockam/env"
# Run `ockam project enroll ...`
#
# The `project enroll` command creates a new vault and generates a cryptographic identity with
# private keys stored in that vault.
#
# The enrollment ticket includes routes and identifiers for the project membership authority
# and the project's node that offers the relay service.
#
# The enrollment ticket also includes an enrollment token. The project enroll command
# creates a secure channel with the project membership authority and presents this enrollment token.
# The authority enrolls presented identity and returns a project membership credential.
#
# The command, stores this credential for later use and exits.
ockam project enroll "$ENROLLMENT_TICKET"
# Create an ockam node.
#
# Create an access control policy that only allows project members that possesses a credential with
# attribute mongodb-outlet="true" to connect to TCP Portal Inlets on this node.
#
# Create a TCP Portal Inlet to MongoDB.
# This makes the remote MongoDB available on all localhost IPs at - 0.0.0.0:17017
ockam node create
ockam policy create --resource tcp-inlet --expression '(= subject.mongodb-outlet "true")'
ockam tcp-inlet create --from 0.0.0.0:17017 --via mongodb
EOS
105 changes: 105 additions & 0 deletions examples/command/portals/databases/mongodb/amazon_vpc/bank_corp/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env bash
set -ex

run() {
enrollment_ticket="$1"

# ----------------------------------------------------------------------------------------------------------------
# CREATE NETWORK

# Create a new VPC and tag it.
vpc_id=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --query 'Vpc.VpcId')
aws ec2 create-tags --resources "$vpc_id" --tags "Key=Name,Value=${name}-vpc"

# Create and Internet Gateway and attach it to the VPC.
gw_id=$(aws ec2 create-internet-gateway --query 'InternetGateway.InternetGatewayId')
aws ec2 attach-internet-gateway --vpc-id "$vpc_id" --internet-gateway-id "$gw_id"

# Create a route table and a route to the Internet through the Gateway.
rtb_id=$(aws ec2 create-route-table --vpc-id "$vpc_id" --query 'RouteTable.RouteTableId')
aws ec2 create-route --route-table-id "$rtb_id" --destination-cidr-block 0.0.0.0/0 --gateway-id "$gw_id"

# Create a subnet and associate the route table
az=$(aws ec2 describe-availability-zones --query "AvailabilityZones[0].ZoneName")
subnet_id=$(aws ec2 create-subnet --vpc-id "$vpc_id" --cidr-block 10.0.0.0/25 \
--availability-zone "$az" --query 'Subnet.SubnetId')
aws ec2 modify-subnet-attribute --subnet-id "$subnet_id" --map-public-ip-on-launch
aws ec2 associate-route-table --subnet-id "$subnet_id" --route-table-id "$rtb_id"

# Create a security group to allow:
# - TCP egress to the Internet
# - No inbound connection
sg_id=$(aws ec2 create-security-group --group-name "${name}-sg" --vpc-id "$vpc_id" --query 'GroupId' \
--description "Allow TCP egress and Postgres ingress")
aws ec2 authorize-security-group-egress --group-id "$sg_id" --cidr 0.0.0.0/0 --protocol tcp --port 0-65535


# ----------------------------------------------------------------------------------------------------------------
# CREATE INSTANCE

ami_id=$(aws ec2 describe-images --owners 137112412989 --query "Images | sort_by(@, &CreationDate) | [-1].ImageId" \
--filters "Name=name,Values=al2023-ami-2023*" "Name=architecture,Values=x86_64" \
"Name=virtualization-type,Values=hvm" "Name=root-device-type,Values=ebs" )

sed "s/\$ENROLLMENT_TICKET/${enrollment_ticket}/g" run_ockam.sh > user_data.sh
instance_id=$(aws ec2 run-instances --image-id "$ami_id" --instance-type c5n.large \
--subnet-id "$subnet_id" --security-group-ids "$sg_id" \
--user-data file://user_data.sh --query 'Instances[0].InstanceId')
aws ec2 create-tags --resources "$instance_id" --tags "Key=Name,Value=${name}-ec2-instance"
aws ec2 wait instance-running --instance-ids "$instance_id"
rm -f user_data.sh
}

cleanup() {
# ----------------------------------------------------------------------------------------------------------------
# DELETE INSTANCE

rm -f user_data.sh
instance_ids=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=${name}-ec2-instance" \
--query "Reservations[*].Instances[*].InstanceId")
for i in $instance_ids; do
aws ec2 terminate-instances --instance-ids "$i"
aws ec2 wait instance-terminated --instance-ids "$i"
done

# ----------------------------------------------------------------------------------------------------------------
# DELETE NETWORK

vpc_ids=$(aws ec2 describe-vpcs --query 'Vpcs[*].VpcId' --filters "Name=tag:Name,Values=${name}-vpc")

for vpc_id in $vpc_ids; do
internet_gateways=$(aws ec2 describe-internet-gateways --query "InternetGateways[*].InternetGatewayId" \
--filters Name=attachment.vpc-id,Values="$vpc_id")
for i in $internet_gateways; do
aws ec2 detach-internet-gateway --internet-gateway-id "$i" --vpc-id "$vpc_id"
aws ec2 delete-internet-gateway --internet-gateway-id "$i"
done

subnet_ids=$(aws ec2 describe-subnets --query "Subnets[*].SubnetId" --filters Name=vpc-id,Values="$vpc_id")
for i in $subnet_ids; do aws ec2 delete-subnet --subnet-id "$i"; done

route_tables=$(aws ec2 describe-route-tables --filters Name=vpc-id,Values="$vpc_id" \
--query 'RouteTables[?length(Associations[?Main!=`true`]) > `0` || length(Associations) == `0`].RouteTableId')
for i in $route_tables; do aws ec2 delete-route-table --route-table-id "$i" || true; done

security_groups=$(aws ec2 describe-security-groups --filters Name=vpc-id,Values="$vpc_id" \
--query "SecurityGroups[?!contains(GroupName, 'default')].[GroupId]")
for i in $security_groups; do aws ec2 delete-security-group --group-id "$i"; done

if aws ec2 describe-vpcs --vpc-ids "$vpc_id" &>/dev/null; then
aws ec2 delete-vpc --vpc-id "$vpc_id"
fi
done
}

export AWS_PAGER="";
export AWS_DEFAULT_OUTPUT="text";

user=""
command -v sha256sum &>/dev/null && user=$(aws sts get-caller-identity | sha256sum | cut -c 1-20)
command -v shasum &>/dev/null && user=$(aws sts get-caller-identity | shasum -a 256 | cut -c 1-20)
export name="ockam-ex-mongo-db-bank-corp-$user"

# Check if the first argument is "cleanup"
# If it is, call the cleanup function. If not, call the run function.
if [ "$1" = "cleanup" ]; then cleanup; else run "$1"; fi
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/bash
set -ex

# Change into ec2-user's home directory and use sudo to run the commands as ec2-user
cd /home/ec2-user
sudo -u ec2-user bash << 'EOS'
set -ex
# Install MongoDB https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-amazon/#install-mongodb-community-edition
sudo tee /etc/yum.repos.d/mongodb-org-7.1.repo > /dev/null <<EOF
[mongodb-org-7.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2023/mongodb-org/7.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://pgp.mongodb.com/server-7.0.asc
EOF
sudo dnf install -y mongodb-org mongodb-mongosh-shared-openssl3 openssl mongodb-org-database-tools-extra mongodb-database-tools mongodb-org-tools mongodb-org-server mongodb-org-mongos mongodb-org-database
sudo systemctl restart mongod
# Install Ockam Command
curl --proto '=https' --tlsv1.2 -sSfL https://install.command.ockam.io | bash
source "$HOME/.ockam/env"
# Run `ockam project enroll ...`
#
# The `project enroll` command creates a new vault and generates a cryptographic identity with
# private keys stored in that vault.
#
# The enrollment ticket includes routes and identitifiers for the project membership authority
# and the project's node that offers the relay service.
#
# The enrollment ticket also includes an enrollment token. The project enroll command
# creates a secure channel with the project membership authority and presents this enrollment token.
# The authority enrolls presented identity and returns a project membership credential.
#
# The command, stores this credential for later use and exits.
ockam project enroll "$ENROLLMENT_TICKET"
# Create an ockam node.
#
# Create an access control policy that only allows project members that possesses a credential with
# attribute mongodb-inlet="true" to connect to TCP Portal Inlets on this node.
#
# Create a TCP Portal Outlet to mongodb.
# This makes the remote mongodb available on all localhost IPs at - 0.0.0.0:17017
ockam node create
ockam relay create mongodb
ockam policy create --resource tcp-outlet --expression '(= subject.mongodb-inlet "true")'
ockam tcp-outlet create --to "127.0.0.1:27017"
EOS
Loading

0 comments on commit ea2689e

Please sign in to comment.