amazon web services - How can I create a TLSSSL connection to a mongodb instance on AWS with a certificate made by certificate m

admin2025-04-17  3

I am trying to deploy a publicly accessible MongoDB instance on AWS, I have a terraform config to deploy this:

terraform {
  backend "s3" {
    bucket  = "terraform-state"
    key     = "mongodb/terraform.tfstate"
    region  = "eu-west-2"
    encrypt = "true"
  }
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.78.0"
    }
  }
  required_version = ">= 0.14.5"
}

provider "aws" {
  region = "eu-west-2" # Specify your desired AWS region

  default_tags {
    tags = {
      CreatedBy = "Tom McLean"
      Terraform = "true"
    }
  }
}

resource "aws_security_group" "alb_sg" {
  name_prefix = "mongodb-alb-sg-"
  vpc_id      = var.vpc_id
  ingress {
    from_port   = 27017
    to_port     = 27017
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group" "lb_sg" {
  name_prefix = "mongodb-lb-sg"
  vpc_id = var.vpc_id
  ingress {
    from_port = 27017
    to_port = 27017
    protocol = "tcp"
    security_groups = [aws_security_group.alb_sg.id]
  }

  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group" "mongodb_sg" {
  name        = "mongodb-security-group"
  description = "Security group for MongoDB"
  vpc_id = var.vpc_id

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 27017
    to_port     = 27017
    protocol    = "tcp"
    security_groups = [aws_security_group.lb_sg.id]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = -1
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "mongodb" {
  ami             = "ami-091f18e98bc129c4e" # Ubuntu
  instance_type   = var.instance_type
  vpc_security_group_ids = [aws_security_group.mongodb_sg.id]
  subnet_id = element(var.subnet_ids, 0)
  user_data = templatefile("${path.module}/user-data.sh", {
    device_name    = var.device_name,
    MONGO_USER     = var.mongo_user,
    MONGO_PASSWORD = var.mongo_password
    MONGO_VERSION = var.mongo_version
  })
  user_data_replace_on_change = true

  root_block_device {
    volume_size = 32
    volume_type = "gp2"
    delete_on_termination = false
  }

  tags = {
    Name = "MongoDB"
  }
}

resource "aws_ebs_volume" "mongodb_volume" {
  availability_zone = aws_instance.mongodb.availability_zone
  size              = var.ebs_size
  type              = "gp2"
  tags = {
    Name = "MongoDB-EBS"
  }
}

resource "aws_volume_attachment" "mongodb_attachment" {
  device_name = var.device_name
  volume_id   = aws_ebs_volume.mongodb_volume.id
  instance_id = aws_instance.mongodb.id
}

resource "aws_lb" "mongodb_lb" {
  name = "mongodb-lb"
  internal = false
  load_balancer_type = "network"
  security_groups = [aws_security_group.alb_sg.id]
  subnets = var.subnet_ids
}

resource "aws_lb_target_group" "mongodb_tg" {
  name = "mongodb-tg"
  port = 27017
  protocol = "TCP"
  vpc_id = var.vpc_id
  target_type = "instance"

  health_check {
    healthy_threshold   = 3
    interval            = 30
    port                = 27017
    protocol            = "TCP"
    timeout             = 5
    unhealthy_threshold = 3
  }

  tags = {
    Name = "MongoDB-tg"
  }
}

resource "aws_lb_target_group_attachment" "mongodb_attachment" {
  target_group_arn = aws_lb_target_group.mongodb_tg.arn
  target_id = aws_instance.mongodb.id
  port = 27017
}

resource "aws_lb_listener" "mongodb_listener" {
  load_balancer_arn = aws_lb.mongodb_lb.arn
  protocol = "TLS"
  port = 27017
  ssl_policy = "ELBSecurityPolicy-2016-08"
  certificate_arn = var.certificate_arn

  default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.mongodb_tg.arn
  }
}

resource "aws_route53_record" "mongodb_dns" {
  zone_id = data.aws_route53_zone.main.zone_id
  name = "${var.domain_prefix}.${var.domain_name}"
  type = "A"

  alias {
    name = aws_lb.mongodb_lb.dns_name
    zone_id = aws_lb.mongodb_lb.zone_id
    evaluate_target_health = true
  }
}

data "aws_route53_zone" "main" {
    name = "${var.domain_name}"
    private_zone = false
}

With user-data.sh being:

#!/bin/bash

# Install docker
apt-get update -y
apt-get install -y docker.io
systemctl start docker
usermod -aG docker ubuntu

DEVICE="${device_name}"
MOUNT_POINT="/var/lib/mongodb"

# Wait for the device to become available
while [ ! -e "$DEVICE" ]; do
    echo "$DEVICE not yet available, waiting..."
    sleep 5
done

mkdir -p $MOUNT_POINT

# Format the volume if it's not formatted yet
if ! blkid $DEVICE | grep ext4 > /dev/null; then
    mkfs.ext4 $DEVICE
fi

mount $DEVICE $MOUNT_POINT

# Ensure the volume mounts automatically after reboot
echo "$DEVICE $MOUNT_POINT ext4 defaults,nofail,x-systemd.device-timeout=10s 0 2" >> /etc/fstab

resize2fs $DEVICE

chown -R 999:999 $MOUNT_POINT

# Create a systemd service for MongoDB
cat > /etc/systemd/system/mongodb.service <<EOL
[Unit]
Description=MongoDB container
After=docker.service
Requires=docker.service

[Service]
Restart=always
ExecStartPre=-/usr/bin/docker rm -f mongodb
ExecStart=/usr/bin/docker run --name=mongodb \
  -p 27017:27017 \
  -v $MOUNT_POINT:/data/db \
  -e MONGO_INITDB_ROOT_USERNAME=${MONGO_USER} \
  -e MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD} \
  --user 999:999 \
  mongo:${MONGO_VERSION}
ExecStop=/usr/bin/docker stop mongodb

[Install]
WantedBy=multi-user.target
EOL

# Enable and start MongoDB systemd service
systemctl daemon-reload
sysemctl enable mongodb
systemctl start mongodb

I can see that the instance is running the mongodb docker container, and listening on port 27017:

ubuntu@ip:~$ docker container ls
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                           NAMES
49e5ed319c76   mongo:latest   "docker-entrypoint.s…"   10 minutes ago   Up 10 minutes   0.0.0.0:27017->27017/tcp, :::27017->27017/tcp   mongodb

However the health check is failing:

The alternative solutions i've considered are to use an application load balancer, but they dont work on TCP connections and I've considered doing the certificate stuff on the mongo instance it's self, however I cant download the .pem file for my domain certificate as it is issued by amazon certificate manager. How can I do a TLS/SSL connection to my mongodb instance in AWS?

I am trying to deploy a publicly accessible MongoDB instance on AWS, I have a terraform config to deploy this:

terraform {
  backend "s3" {
    bucket  = "terraform-state"
    key     = "mongodb/terraform.tfstate"
    region  = "eu-west-2"
    encrypt = "true"
  }
}

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.78.0"
    }
  }
  required_version = ">= 0.14.5"
}

provider "aws" {
  region = "eu-west-2" # Specify your desired AWS region

  default_tags {
    tags = {
      CreatedBy = "Tom McLean"
      Terraform = "true"
    }
  }
}

resource "aws_security_group" "alb_sg" {
  name_prefix = "mongodb-alb-sg-"
  vpc_id      = var.vpc_id
  ingress {
    from_port   = 27017
    to_port     = 27017
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group" "lb_sg" {
  name_prefix = "mongodb-lb-sg"
  vpc_id = var.vpc_id
  ingress {
    from_port = 27017
    to_port = 27017
    protocol = "tcp"
    security_groups = [aws_security_group.alb_sg.id]
  }

  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group" "mongodb_sg" {
  name        = "mongodb-security-group"
  description = "Security group for MongoDB"
  vpc_id = var.vpc_id

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 27017
    to_port     = 27017
    protocol    = "tcp"
    security_groups = [aws_security_group.lb_sg.id]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = -1
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "mongodb" {
  ami             = "ami-091f18e98bc129c4e" # Ubuntu
  instance_type   = var.instance_type
  vpc_security_group_ids = [aws_security_group.mongodb_sg.id]
  subnet_id = element(var.subnet_ids, 0)
  user_data = templatefile("${path.module}/user-data.sh", {
    device_name    = var.device_name,
    MONGO_USER     = var.mongo_user,
    MONGO_PASSWORD = var.mongo_password
    MONGO_VERSION = var.mongo_version
  })
  user_data_replace_on_change = true

  root_block_device {
    volume_size = 32
    volume_type = "gp2"
    delete_on_termination = false
  }

  tags = {
    Name = "MongoDB"
  }
}

resource "aws_ebs_volume" "mongodb_volume" {
  availability_zone = aws_instance.mongodb.availability_zone
  size              = var.ebs_size
  type              = "gp2"
  tags = {
    Name = "MongoDB-EBS"
  }
}

resource "aws_volume_attachment" "mongodb_attachment" {
  device_name = var.device_name
  volume_id   = aws_ebs_volume.mongodb_volume.id
  instance_id = aws_instance.mongodb.id
}

resource "aws_lb" "mongodb_lb" {
  name = "mongodb-lb"
  internal = false
  load_balancer_type = "network"
  security_groups = [aws_security_group.alb_sg.id]
  subnets = var.subnet_ids
}

resource "aws_lb_target_group" "mongodb_tg" {
  name = "mongodb-tg"
  port = 27017
  protocol = "TCP"
  vpc_id = var.vpc_id
  target_type = "instance"

  health_check {
    healthy_threshold   = 3
    interval            = 30
    port                = 27017
    protocol            = "TCP"
    timeout             = 5
    unhealthy_threshold = 3
  }

  tags = {
    Name = "MongoDB-tg"
  }
}

resource "aws_lb_target_group_attachment" "mongodb_attachment" {
  target_group_arn = aws_lb_target_group.mongodb_tg.arn
  target_id = aws_instance.mongodb.id
  port = 27017
}

resource "aws_lb_listener" "mongodb_listener" {
  load_balancer_arn = aws_lb.mongodb_lb.arn
  protocol = "TLS"
  port = 27017
  ssl_policy = "ELBSecurityPolicy-2016-08"
  certificate_arn = var.certificate_arn

  default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.mongodb_tg.arn
  }
}

resource "aws_route53_record" "mongodb_dns" {
  zone_id = data.aws_route53_zone.main.zone_id
  name = "${var.domain_prefix}.${var.domain_name}"
  type = "A"

  alias {
    name = aws_lb.mongodb_lb.dns_name
    zone_id = aws_lb.mongodb_lb.zone_id
    evaluate_target_health = true
  }
}

data "aws_route53_zone" "main" {
    name = "${var.domain_name}"
    private_zone = false
}

With user-data.sh being:

#!/bin/bash

# Install docker
apt-get update -y
apt-get install -y docker.io
systemctl start docker
usermod -aG docker ubuntu

DEVICE="${device_name}"
MOUNT_POINT="/var/lib/mongodb"

# Wait for the device to become available
while [ ! -e "$DEVICE" ]; do
    echo "$DEVICE not yet available, waiting..."
    sleep 5
done

mkdir -p $MOUNT_POINT

# Format the volume if it's not formatted yet
if ! blkid $DEVICE | grep ext4 > /dev/null; then
    mkfs.ext4 $DEVICE
fi

mount $DEVICE $MOUNT_POINT

# Ensure the volume mounts automatically after reboot
echo "$DEVICE $MOUNT_POINT ext4 defaults,nofail,x-systemd.device-timeout=10s 0 2" >> /etc/fstab

resize2fs $DEVICE

chown -R 999:999 $MOUNT_POINT

# Create a systemd service for MongoDB
cat > /etc/systemd/system/mongodb.service <<EOL
[Unit]
Description=MongoDB container
After=docker.service
Requires=docker.service

[Service]
Restart=always
ExecStartPre=-/usr/bin/docker rm -f mongodb
ExecStart=/usr/bin/docker run --name=mongodb \
  -p 27017:27017 \
  -v $MOUNT_POINT:/data/db \
  -e MONGO_INITDB_ROOT_USERNAME=${MONGO_USER} \
  -e MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD} \
  --user 999:999 \
  mongo:${MONGO_VERSION}
ExecStop=/usr/bin/docker stop mongodb

[Install]
WantedBy=multi-user.target
EOL

# Enable and start MongoDB systemd service
systemctl daemon-reload
sysemctl enable mongodb
systemctl start mongodb

I can see that the instance is running the mongodb docker container, and listening on port 27017:

ubuntu@ip:~$ docker container ls
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                           NAMES
49e5ed319c76   mongo:latest   "docker-entrypoint.s…"   10 minutes ago   Up 10 minutes   0.0.0.0:27017->27017/tcp, :::27017->27017/tcp   mongodb

However the health check is failing:

The alternative solutions i've considered are to use an application load balancer, but they dont work on TCP connections and I've considered doing the certificate stuff on the mongo instance it's self, however I cant download the .pem file for my domain certificate as it is issued by amazon certificate manager. How can I do a TLS/SSL connection to my mongodb instance in AWS?

Share Improve this question edited Feb 1 at 16:56 Mark B 202k27 gold badges334 silver badges329 bronze badges Recognized by AWS Collective asked Feb 1 at 16:03 Tom McLeanTom McLean 6,3611 gold badge21 silver badges51 bronze badges 4
  • I have no clue about docker, but it looks like you don't specify any server certificate to the MongoDB service. Maybe try to run mongod directly instead of using docker? – Wernfried Domscheit Commented Feb 1 at 16:18
  • Yeah, I cant get access to the certificate for my domain from AWS certificate manager, if I wanted to access my mongodb instance from my domain name, would I need access to the certificate? I'm quite new to networking so I am not 100% sure what I need to do to get it to work – Tom McLean Commented Feb 1 at 16:23
  • I was hoping that I would be able to run the mongo instance without certificates, and use the NLB to handle the certificates stuff, converting the TLS traffic into TCP to forward to the mongo instance – Tom McLean Commented Feb 1 at 16:29
  • I assume, the connection between your MongoDB client and the NLB will be properly TLS/SSL encrypted. However, other functions (e.g. x.509 Certificates to Authenticate Clients) may not work, because from mongod point of view TLS/SSL is not enabled. – Wernfried Domscheit Commented Feb 3 at 11:51
Add a comment  | 

1 Answer 1

Reset to default 1

You have two security groups alb_sg and lb_sg that have the same security group rules. Then you have a mongodb_sg security group that only allows MongoDB traffic from the lb_sg security group.

You are assigning alb_sg to the network load balancer, and you are assigning mongodb_sg to the EC2 instance. So the way you have it currently configured, the load balancer, using alb_sg can't connect to the EC2 instance, which is using mongodb_sg, because the EC2 instance only allows traffic from lb_sg, which isn't assigned to anything.

You need to delete either alb_sg or lb_sg to clear up the confusion, and make sure your EC2 security group allows incoming requests from the security group you actually have assigned to the load balancer.

转载请注明原文地址:http://anycun.com/QandA/1744824387a88125.html