Amazon Web Services

This document describes the process for creating and managing a customer private cloud at Amazon Web Services (AWS).

Create the IAM Roles

Telestream Cloud uses AWS Identity and Access Management (IAM) roles to create and manage a customer private cloud.

Using the AWS console, the AWS command line interface (CLI) or a Terraform script the customer creates IAM roles in their account that delegate specific permissions to the Telestream Cloud AWS account (078992246105).

There are three roles that need to be created by the customer. Each role will be identified by an Amazon Resource Name (ARN) that should be provided to Telestream Cloud support.

bootstrap

The bootstrap role allows Telestream Cloud to create a Virtual Private Cloud (VPC) within the customer AWS account. This role requires the following permissions:

ec2:AllocateAddress
ec2:AssociateRouteTable
ec2:AttachInternetGateway
ec2:AuthorizeSecurityGroupIngress
ec2:CreateInternetGateway
ec2:CreateKeyPair
ec2:CreateNatGateway
ec2:CreateRoute
ec2:CreateRouteTable
ec2:CreateSecurityGroup
ec2:CreateSubnet
ec2:CreateTags
ec2:CreateVpc
ec2:CreateVpcEndpoint
ec2:DescribeAvailabilityZones
ec2:DescribeRouteTables
ec2:ModifySubnetAttribute
ec2:ModifyVpcAttribute

Note that the customer should remove this role once the private cloud has been created. Alternatively Telestream can provide a Terraform script that the customer can use to create the VPC in their account.

autoscaler

The autoscaler role allows Telestream Cloud to create EC2 instances within the customer VPC. This role requires the following permissions:

ec2:CreateTags
ec2:DescribeTags
ec2:RunInstances
ec2:DescribeInstances
ec2:TerminateInstances
ec2:CancelSpotFleetRequests
ec2:RequestSpotFleet
ec2:RequestSpotInstances
ec2:StopInstances
ec2:DescribeSecurityGroups
ec2:DescribeSpotFleetRequests
ec2:DescribeSpotPriceHistory
ec2:DescribeImages
ec2:DescribeSpotFleetInstances
ec2:StartInstances
ec2:DescribeVolumes
ec2:DescribeSubnets
pricing:GetProducts

Instances can be provisioned from on-demand and reserved pools or using a Spot Fleet.

instance

This role allows the instance to attach and detach additional block storage and to manage instance tags. This role requires the following permissions:

ec2:CreateTags
ec2:DeleteTags
ec2:DescribeTags
ec2:DetachVolume
ec2:AttachVolume
ec2:CreateVolume
ec2:DeleteVolume
ec2:DescribeVolumes
ec2:ModifyInstanceAttribut

The instance role is passed to the EC2 instances using an instance profile.

Terraform

Terraform is a third-party Infrastructure tool used to create and manage cloud infrastructure. The following Terraform script can be used by the customer to create the required IAM roles:

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

  required_version = ">= 0.14.9"
}

provider "aws" {
  profile = "default"
  region  = "us-west-2"
}

data "aws_caller_identity" "current" {}

resource "aws_iam_role" "telestream_cloud_role_bootstrap" {
  name = "telestream-cloud-bootstrap"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          AWS = "arn:aws:iam::078992246105:root"
        }
      },
    ]
  })

  inline_policy {
    # Policy needed to fully bootstrap a VPC. May be removed after setup has been completed.
    name = "bootstrap_policy"

    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect   = "Allow"
          Resource = "*"
          Action = [
            "ec2:AllocateAddress",
            "ec2:AssociateRouteTable",
            "ec2:AttachInternetGateway",
            "ec2:AuthorizeSecurityGroupIngress",
            "ec2:CreateInternetGateway",
            "ec2:CreateKeyPair",
            "ec2:CreateNatGateway",
            "ec2:CreateRoute",
            "ec2:CreateRouteTable",
            "ec2:CreateSecurityGroup",
            "ec2:CreateSubnet",
            "ec2:CreateTags",
            "ec2:CreateVpc",
            "ec2:CreateVpcEndpoint",
            "ec2:DescribeAvailabilityZones",
            "ec2:DescribeRouteTables",
            "ec2:ModifySubnetAttribute",
            "ec2:ModifyVpcAttribute"
          ]
        },
      ]
    })
  }
}

resource "aws_iam_role" "telestream_cloud_role_instance" {
  name = "telestream-cloud-instance"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          AWS = "arn:aws:iam::078992246105:root"
        }
      },
    ]
  })

  inline_policy {
    # Policy used by worker instances. It is mainly used for instances to attached volumes to themselves. It is needed only for certain services.
    name = "instance_policy"

    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect   = "Allow"
          Resource = "*"
          Action = [
            "ec2:CreateTags",
            "ec2:DeleteTags",
            "ec2:DescribeTags",
            "ec2:DetachVolume",
            "ec2:AttachVolume",
            "ec2:CreateVolume",
            "ec2:DeleteVolume",
            "ec2:DescribeVolumes",
            "ec2:ModifyInstanceAttribute"
          ]
        },
      ]
    })
  }
}


resource "aws_iam_role" "telestream_cloud_role_autoscaling" {
  name = "telestream-cloud-autoscaling"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        "Effect" = "Allow",
        "Principal" = {
          "Service" = "ec2.amazonaws.com"
        },
        "Action" = "sts:AssumeRole"
      },
      {
        "Sid"    = "",
        "Effect" = "Allow",
        "Principal" = {
          "Service" = "spotfleet.amazonaws.com"
        },
        "Action" = "sts:AssumeRole"
      },
      {
        "Effect" = "Allow",
        "Principal" = {
          "AWS" = "arn:aws:iam::078992246105:root"
        },
        "Action" = "sts:AssumeRole"
      }
    ]
  })

  inline_policy {
    # Policy used by worker instances. It is mainly used for instances to attached volumes to themselves. It is needed only for certain services.
    name = "autoscaler_policy"

    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Sid    = "VisualEditor1"
          Effect = "Allow"
          Action = [
            "ec2:CreateTags",
            "ec2:DescribeTags",
            "ec2:RunInstances",
            "ec2:DescribeInstances",
            "ec2:TerminateInstances",
            "ec2:CancelSpotFleetRequests",
            "ec2:RequestSpotFleet",
            "ec2:RequestSpotInstances",
            "ec2:StopInstances",
            "ec2:DescribeSecurityGroups",
            "ec2:DescribeSpotFleetRequests",
            "ec2:DescribeSpotPriceHistory",
            "ec2:DescribeImages",
            "ec2:DescribeSpotFleetInstances",
            "ec2:StartInstances",
            "ec2:DescribeVolumes",
            "ec2:DescribeSubnets",
            "pricing:GetProducts"
          ]
          Resource = "*"
        },
        {
          Sid    = "VisualEditor2",
          Effect = "Allow",
          Action = "iam:PassRole",
          Condition = {
            StringEquals = {
              "iam:PassedToService" = [
                "ec2.amazonaws.com"
              ]
            }
          },
          Resource = [
            "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/telestream-cloud-autoscaling",
            "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/telestream-cloud-instance"
          ]
        }
      ]
    })
  }
}

output "bootstrap_role" {
  value       = aws_iam_role.telestream_cloud_role_bootstrap.arn
  description = "ARN of the IAM role used by during setup, may be later removed"
}

output "instance_role" {
  value       = aws_iam_role.telestream_cloud_role_instance.arn
  description = "ARN of the IAM role attached to EC2 instances created by Telestream Cloud Autoscaler"
}

output "autoscaling_role" {
  value       = aws_iam_role.telestream_cloud_role_autoscaling.arn
  description = "ARN of the IAM role used by Telestream Cloud Autoscaler"
}

Use the following command to run the Terraform script. Visit AWS Terraform Tutorial for additional details.

$ terraform init 
$ terraform plan 
604604
$ terraform apply 
604604

If the script executes successfully it will produce output similar to the following:

Navigate to directory and confirm main.tf file is present.
*****************************************************************************************************************************************************************************

$ ls -l

total 135784
-rw-r--r--  1 root  1195003546      5601 Dec 15 07:30 main.tf
[email protected] 1 root  1195003546  69501360 Dec  8 13:15 terraform



Run and initialize Terraform. 
*****************************************************************************************************************************************************************************


$ ./terraform init -input=false

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 3.27"...
- Installing hashicorp/aws v3.69.0...
- Installed hashicorp/aws v3.69.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.





Create a Terraform plan based off of main.tf parameters.
*****************************************************************************************************************************************************************************


$ ./terraform plan -out=tfplan -input=false

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_iam_role.telestream_cloud_role_autoscaling will be created
  + resource "aws_iam_role" "telestream_cloud_role_autoscaling" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "ec2.amazonaws.com"
                        }
                    },
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "spotfleet.amazonaws.com"
                        }
                      + Sid       = ""
                    },
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + AWS = "arn:aws:iam::XXXXXXXXXXXX:root"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "telestream-cloud-autoscaling"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = (known after apply)
      + unique_id             = (known after apply)

      + inline_policy {
          + name   = "autoscaler_policy"
          + policy = jsonencode(
                {
                  + Statement = [
                      + {
                          + Action   = [
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "pricing: XXXXXXXXXXXX",
                            ]
                          + Effect   = "Allow"
                          + Resource = "*"
                          + Sid      = "VisualEditor1"
                        },
                      + {
                          + Action    = "iam:PassRole"
                          + Condition = {
                              + StringEquals = {
                                  + iam:PassedToService = [
                                      + "ec2.amazonaws.com",
                                    ]
                                }
                            }
                          + Effect    = "Allow"
                          + Resource  = [
                              + "arn:aws:iam::XXXXXXXXXXXX:role/telestream-cloud-autoscaling",
                              + "arn:aws:iam::XXXXXXXXXXXX:role/telestream-cloud-instance",
                            ]
                          + Sid       = "VisualEditor2"
                        },
                    ]
                  + Version   = "2012-10-17"
                }
            )
        }
    }

  # aws_iam_role.telestream_cloud_role_bootstrap will be created
  + resource "aws_iam_role" "telestream_cloud_role_bootstrap" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + AWS = "arn:aws:iam:: XXXXXXXXXXXX:root"
                        }
                      + Sid       = ""
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "telestream-cloud-bootstrap"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = (known after apply)
      + unique_id             = (known after apply)

      + inline_policy {
          + name   = "bootstrap_policy"
          + policy = jsonencode(
                {
                  + Statement = [
                      + {
                          + Action   = [
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                            ]
                          + Effect   = "Allow"
                          + Resource = "*"
                        },
                    ]
                  + Version   = "2012-10-17"
                }
            )
        }
    }

  # aws_iam_role.telestream_cloud_role_instance will be created
  + resource "aws_iam_role" "telestream_cloud_role_instance" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + AWS = "arn:aws:iam:: XXXXXXXXXXXX:root"
                        }
                      + Sid       = ""
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "telestream-cloud-instance"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = (known after apply)
      + unique_id             = (known after apply)

      + inline_policy {
          + name   = "instance_policy"
          + policy = jsonencode(
                {
                  + Statement = [
                      + {
                          + Action   = [
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                              + "ec2: XXXXXXXXXXXX",
                            ]
                          + Effect   = "Allow"
                          + Resource = "*"
                        },
                    ]
                  + Version   = "2012-10-17"
                }
            )
        }
    }

Plan: 3 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + autoscaling_role = (known after apply)
  + bootstrap_role   = (known after apply)
  + instance_role    = (known after apply)

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"





Check and confirm that tfplan file is generated.
*****************************************************************************************************************************************************************************

$ ls -l

total 135784
-rw-r--r--  1 root  1195003546      5601 Dec 15 07:30 main.tf
[email protected] 1 root  1195003546  69501360 Dec  8 13:15 terraform
-rw-r--r--  1 root  1195003546      4383 Dec 15 07:38 tfplan





Run newly created Terraform Plan "tfplan".
*****************************************************************************************************************************************************************************

$ ./terraform apply -input=false tfplan

aws_iam_role.telestream_cloud_role_instance: Creating...
aws_iam_role.telestream_cloud_role_autoscaling: Creating...
aws_iam_role.telestream_cloud_role_bootstrap: Creating...
aws_iam_role.telestream_cloud_role_autoscaling: Creation complete after 2s [id=telestream-cloud-autoscaling]
aws_iam_role.telestream_cloud_role_instance: Creation complete after 2s [id=telestream-cloud-instance]
aws_iam_role.telestream_cloud_role_bootstrap: Creation complete after 2s [id=telestream-cloud-bootstrap]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

autoscaling_role = "arn:aws:iam::XXXXXXXXXXXX:role/telestream-cloud-autoscaling"
bootstrap_role = "arn:aws:iam::XXXXXXXXXXXX:role/telestream-cloud-bootstrap"
instance_role = "arn:aws:iam::XXXXXXXXXXXX:role/telestream-cloud-instance"




Confirm current terraform.tfstate file is created and save for reference.
*****************************************************************************************************************************************************************************

$ ls -l

total 135824
-rw-r--r--  1 root  1195003546      5601 Dec 15 07:30 main.tf
[email protected] 1 root  1195003546  69501360 Dec  8 13:15 terraform
-rw-r--r--  1 root  1195003546      7092 Dec 15 07:39 terraform.tfstate
-rw-r--r--  1 root  1195003546      4383 Dec 15 07:38 tfplan






Please provide the 3 ARN role information to be used for VPC configuration to Telestream engineers.
*****************************************************************************************************************************************************************************

autoscaling_role = "arn:aws:iam::XXXXXXXXXXXX:role/telestream-cloud-autoscaling"
bootstrap_role = "arn:aws:iam::XXXXXXXXXXXX:role/telestream-cloud-bootstrap"
instance_role = "arn:aws:iam::XXXXXXXXXXXX:role/telestream-cloud-instance"

Send the ARN for each role to the Telestream Support Team at [[email protected]].