Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
DonFreed committed Jun 14, 2023
0 parents commit de760f7
Show file tree
Hide file tree
Showing 3 changed files with 494 additions and 0 deletions.
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Sentieon - Terraform
Terraform configuration files for the Sentieon software

## Introduction

[Terraform](https://www.terraform.io/) is an open-source infrastructure as code (IaC) tool for the provisioning and management of cloud infrastructure. This repository contains example terraform configuration files that can be used to quickly deploy the Sentieon software to your cloud infrastructure.

## Quick Start - Sentieon License server deployment to AWS

### Requirements

* The [Terraform CLI](https://developer.hashicorp.com/terraform/downloads)
* The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
* An AWS account and credentials with permission to provision resources inside the account
* A Sentieon license file for your FQDN, bound to port 8990 and placed in your s3 bucket

### Provision the license server

Use the terraform configuration files to provision the following infrastructure:
* Security groups for the Sentieon license server and any compute nodes
* A CloudWatch log group for the license server logs
* An IAM role and instance profile for the license server
* Granting read access to the Sentieon software package and license file in AWS s3
* Granting write access to the CloudWatch log group
* Starts a t3.nano ec2 instance to host the license server, using the IAM profile and security group
* Using the latest Amazon Linux 2023 AMI for the region
* Uses an encrypted root EBS disk with either an AWS-managed or (optionally) a customer-managed key
* Has a user data script to do the following at startup, without direct user intervention:
* Install, configure, and start the cloudwatch universal agent to push the license server logs to CloudWatch
* Download the customer's license file from s3
* Download and install the Sentieon software. Start the license server using the license file
* Create a private hosted zone with AWS Route 53
* Create a Route53 record associating the FQDN with the private IP of the license server instance


```bash
git clone https://github.com/sentieon/terraform
cd terraform/aws_license-server

# Configure your AWS credentials
export AWS_ACCESS_KEY_ID=<AWS_ACCESS_KEY_ID>
export AWS_SECRET_ACCESS_KEY=<AWS_SECRET_ACCESS_KEY>

# Initialize the directory with Terraform
terraform init

# Provision the license server infrastructure
terraform apply \
-var 'aws_region=<AWS_REGION>' \
-var 'licsrvr_fqdn=<FQDN>' \
-var 'license_s3_uri=s3://<S3_URI>'
```

The infrastructure should startup within a few minutes.

AWS will charge your account for deployed infrastructure including the ec2 instance, EBS disk, Route53 hosted zone. The deployment will also generate charges for DNS queries resolved by Route53.

### Cleanup

The provisioned infrastructure can be destroyed with the `terraform apply -destroy` command:
```bash
terraform apply -destroy \
-var 'aws_region=<AWS_REGION>' \
-var 'licsrvr_fqdn=<FQDN>' \
-var 'license_s3_uri=s3://<S3_URI>'
```
216 changes: 216 additions & 0 deletions aws_license-server/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
variable "aws_region" {}
variable "licsrvr_fqdn" {}
variable "license_s3_uri" {}
variable "kms_key" {
type = string
default = null
}
variable "sentieon_version" {
type = string
default = "202112.07"
}

locals {
license_bucket_arn = format("arn:aws:s3:::%s", split("/", var.license_s3_uri)[2])
license_obj_arn = format("arn:aws:s3:::%s", join("/", slice(split("/", var.license_s3_uri), 2, 5)))
}

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
dns = {
source = "hashicorp/dns"
}
}

required_version = ">= 1.2.0"
}

provider "aws" {
region = var.aws_region
}

# Find the IP of the master server
data "dns_a_record_set" "master" {
host = "master.sentieon.com"
}

# Find the default VPC
data "aws_vpc" "default" {
default = true
}

# Find the AWS account ID
data "aws_caller_identity" "current" {}

## Configure the security group for the license server
# Create a security group
resource "aws_security_group" "sentieon_license_server" {
name = "sentieon_license_server"
description = "Security groups for the Sentieon license server"
vpc_id = data.aws_vpc.default.id
}

# Create a security group for the compute nodes
resource "aws_security_group" "sentieon_compute_nodes" {
name = "sentieon_compute"
description = "Security groups for Sentieon compute nodes"
vpc_id = data.aws_vpc.default.id
}

# Security group rules are definied in a separate file

# Cloudwatch log group for logs
resource "aws_cloudwatch_log_group" "licsrvr" {
name = "/sentieon/licsrvr/LicsrvrLog"
}

# IAM role for the license server
resource "aws_iam_role" "licsrvr" {
name = "sentieon_licsrvr_role"

# Allow policy to be assumed by ec2 instances
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "ec2.amazonaws.com"
}
},
]
})

# s3 access to the license file in s3 and Sentieon software
inline_policy {
name = "s3_inline_policy"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = ["s3:Get*", "s3:List*", "s3-object-lambda:Get*", "s3-object-lambda:List*"]
Effect = "Allow"
Resource = [
local.license_bucket_arn,
local.license_obj_arn,
"arn:aws:s3:::sentieon-release",
format("arn:aws:s3:::sentieon-release/software/sentieon-genomics-%s.tar.gz", var.sentieon_version)
]
},
]
})
}

# access to write license server logs to cloudwatch
inline_policy {
name = "cloudwatch_inline_policy"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = ["logs:PutRetentionPolicy", "logs:CreateLogGroup", "logs:PutLogEvents", "logs:CreateLogStream"]
Effect = "Allow"
Resource = [
format("arn:aws:logs:*:%v:log-group:%v", data.aws_caller_identity.current.account_id, aws_cloudwatch_log_group.licsrvr.name),
format("arn:aws:logs:*:%v:log-group:%v:log-stream:*", data.aws_caller_identity.current.account_id, aws_cloudwatch_log_group.licsrvr.name)
]
},
]
})
}
}

resource "aws_iam_instance_profile" "licsrvr" {
name = "sentieon_licsrvr_profile"
role = aws_iam_role.licsrvr.name
}

## Start the License server
# Find the latest Amazon Linux AMI
data "aws_ami" "al2023" {
most_recent = true

filter {
name = "name"
values = ["al2023-ami-2023.*-x86_64"]
}

filter {
name = "virtualization-type"
values = ["hvm"]
}

filter {
name = "architecture"
values = ["x86_64"]
}

owners = ["amazon"]
}

# Create the license server instance
resource "aws_instance" "sentieon_licsrvr" {
ami = data.aws_ami.al2023.id
instance_type = "t3.nano"
vpc_security_group_ids = [aws_security_group.sentieon_license_server.id]
iam_instance_profile = aws_iam_instance_profile.licsrvr.id
user_data_replace_on_change = true

root_block_device {
encrypted = true
kms_key_id = var.kms_key
}

user_data = <<EOF
#!/usr/bin/bash -xv
yum update -y
yum install amazon-cloudwatch-agent -y
mkdir -p /opt/aws/amazon-cloudwatch-agent/bin
echo '{ "agent": { "run_as_user": "root" }, "logs": { "logs_collected": { "files": { "collect_list": [ { "file_path": "/opt/sentieon/licsrvr.log", "log_group_name": "${aws_cloudwatch_log_group.licsrvr.name}", "log_stream_name": "{instance_id}", "retention_in_days": 120 } ] } } } }' > /opt/aws/amazon-cloudwatch-agent/bin/config.json
amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json
mkdir -p /opt/sentieon
cd /opt/sentieon
aws s3 cp 's3://sentieon-release/software/sentieon-genomics-${var.sentieon_version}.tar.gz' - | tar -zxf -
ln -s 'sentieon-genomics-${var.sentieon_version}' 'sentieon-genomics'
aws s3 cp "${var.license_s3_uri}" "./sentieon.lic"
i=0
while true; do
if getent ahosts "${var.licsrvr_fqdn}"; then
break
fi
i=$((i + 1))
if [[ i -gt 300 ]]; then
exit 1
fi
sleep 1
done
sentieon-genomics/bin/sentieon licsrvr --start --log licsrvr.log ./sentieon.lic
EOF
}

## Create a private hosted zone
# Create a hosted zone
resource "aws_route53_zone" "primary" {
name = var.licsrvr_fqdn

vpc {
vpc_id = data.aws_vpc.default.id
vpc_region = var.aws_region
}
}

resource "aws_route53_record" "licsrvr_fqdn" {
zone_id = aws_route53_zone.primary.zone_id
name = var.licsrvr_fqdn
type = "A"
ttl = "300"
records = [aws_instance.sentieon_licsrvr.private_ip]
}
Loading

0 comments on commit de760f7

Please sign in to comment.