mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
Fleet Sandbox (#5079)
* Add code for the shared infra part of the demo environment * Checkin * checkin * Checkin for pre-provisioner, got terraform working * Checkin with the pre-deployer working, now blocked by helm chart * Add interface for helm * Add some initial code for the JIT Provisioner lambda Lots of code taken from https://gitlab.com/hmajid2301/articles/-/tree/master/41.%20Create%20a%20webapp%20with%20fizz * Update helm chart to work with shared infra (#5621) * Update helm chart to work with shared infra * Update helm chart README to reflect changes. * Checkin * Checkin * Checkin, Pre-provisioner actually works * PreProvisioner is now complete * Make changes to the JIT provisioner based off of actually learning how to do stuff * checkin * Check in, broken currently * Add all code except provisioning and emailing user * Checkin * Checkin, fixed kubernetes * Checkin * Forgot a file * Finish jit provisioner, need to test now * Checkin, switching to nginx ingress * Fleets are now actually accessible * JITProvisioner now returns working fleet instances * Deprovisioner code done, just need a few bugs fixed * Fix the deprovisioner so it works now and re-ip * fixup * Finished testing the deprovisioner * Added monitoring and fixed some bugs * Add stuff for #6548 * fixed per luke's suggestion * Fix for inactive task definition arns * move everything to the prod account * Bump fleet version and fix a couple of bugs * Fix a couple of bugs * Lots of security fixes and a few bug fixes * Rename demo to sandbox to match product's naming * Revert "Update helm chart to work with shared infra (#5621)" This reverts commit 610bbd1c00338620f6cc65fe2aff86139551f465. Co-authored-by: Robert Fairburn <8029478+rfairburn@users.noreply.github.com>
This commit is contained in:
parent
f4b20b6ae5
commit
9338fcbcbd
2
infrastructure/sandbox/.gitignore
vendored
Normal file
2
infrastructure/sandbox/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.external_modules
|
||||||
|
.tfsec
|
1
infrastructure/sandbox/JITProvisioner/.gitignore
vendored
Normal file
1
infrastructure/sandbox/JITProvisioner/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.zip
|
270
infrastructure/sandbox/JITProvisioner/deprovisioner.tf
Normal file
270
infrastructure/sandbox/JITProvisioner/deprovisioner.tf
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
data "aws_iam_policy_document" "sfn-assume-role" {
|
||||||
|
statement {
|
||||||
|
actions = ["sts:AssumeRole"]
|
||||||
|
principals {
|
||||||
|
type = "Service"
|
||||||
|
identifiers = ["states.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "sfn" {
|
||||||
|
role = aws_iam_role.sfn.id
|
||||||
|
policy_arn = aws_iam_policy.sfn.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_policy" "sfn" {
|
||||||
|
name = "${local.full_name}-sfn"
|
||||||
|
policy = data.aws_iam_policy_document.sfn.json
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "sfn" {
|
||||||
|
statement {
|
||||||
|
actions = ["ecs:RunTask"]
|
||||||
|
resources = [replace(aws_ecs_task_definition.deprovisioner.arn, "/:\\d+$/", ":*"), replace(aws_ecs_task_definition.deprovisioner.arn, "/:\\d+$/", "")]
|
||||||
|
condition {
|
||||||
|
test = "ArnLike"
|
||||||
|
variable = "ecs:cluster"
|
||||||
|
values = [var.ecs_cluster.arn]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
actions = ["iam:PassRole"]
|
||||||
|
resources = ["*"]
|
||||||
|
condition {
|
||||||
|
test = "StringLike"
|
||||||
|
variable = "iam:PassedToService"
|
||||||
|
values = ["ecs-tasks.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
actions = ["events:PutTargets", "events:PutRule", "events:DescribeRule"]
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role" "sfn" {
|
||||||
|
name = "${local.full_name}-sfn"
|
||||||
|
|
||||||
|
assume_role_policy = data.aws_iam_policy_document.sfn-assume-role.json
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "deprovisioner" {
|
||||||
|
role = aws_iam_role.deprovisioner.id
|
||||||
|
policy_arn = aws_iam_policy.deprovisioner.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_policy" "deprovisioner" {
|
||||||
|
name = "${local.full_name}-deprovisioner"
|
||||||
|
policy = data.aws_iam_policy_document.deprovisioner.json
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "deprovisioner" {
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"dynamodb:List*",
|
||||||
|
"dynamodb:DescribeReservedCapacity*",
|
||||||
|
"dynamodb:DescribeLimits",
|
||||||
|
"dynamodb:DescribeTimeToLive"
|
||||||
|
]
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"dynamodb:BatchGet*",
|
||||||
|
"dynamodb:DescribeStream",
|
||||||
|
"dynamodb:DescribeTable",
|
||||||
|
"dynamodb:Get*",
|
||||||
|
"dynamodb:Query",
|
||||||
|
"dynamodb:Scan",
|
||||||
|
"dynamodb:BatchWrite*",
|
||||||
|
"dynamodb:CreateTable",
|
||||||
|
"dynamodb:Delete*",
|
||||||
|
"dynamodb:Update*",
|
||||||
|
"dynamodb:PutItem"
|
||||||
|
]
|
||||||
|
resources = [var.dynamodb_table.arn]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = [ #tfsec:ignore:aws-iam-no-policy-wildcards
|
||||||
|
"kms:Encrypt*",
|
||||||
|
"kms:Decrypt*",
|
||||||
|
"kms:ReEncrypt*",
|
||||||
|
"kms:GenerateDataKey*",
|
||||||
|
"kms:Describe*"
|
||||||
|
]
|
||||||
|
resources = [aws_kms_key.ecr.arn, var.kms_key.arn]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = ["*"]
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "deprovisioner-assume-role" {
|
||||||
|
statement {
|
||||||
|
actions = ["sts:AssumeRole"]
|
||||||
|
principals {
|
||||||
|
type = "Service"
|
||||||
|
identifiers = ["ecs-tasks.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role" "deprovisioner" {
|
||||||
|
name = "${local.full_name}-deprovisioner"
|
||||||
|
|
||||||
|
assume_role_policy = data.aws_iam_policy_document.deprovisioner-assume-role.json
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_ecs_task_definition" "deprovisioner" {
|
||||||
|
family = "${local.full_name}-deprovisioner"
|
||||||
|
network_mode = "awsvpc"
|
||||||
|
requires_compatibilities = ["FARGATE"]
|
||||||
|
execution_role_arn = aws_iam_role.deprovisioner.arn
|
||||||
|
task_role_arn = aws_iam_role.deprovisioner.arn
|
||||||
|
cpu = 1024
|
||||||
|
memory = 4096
|
||||||
|
container_definitions = jsonencode(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name = "${var.prefix}-deprovisioner"
|
||||||
|
image = docker_registry_image.deprovisioner.name
|
||||||
|
mountPoints = []
|
||||||
|
volumesFrom = []
|
||||||
|
essential = true
|
||||||
|
networkMode = "awsvpc"
|
||||||
|
logConfiguration = {
|
||||||
|
logDriver = "awslogs"
|
||||||
|
options = {
|
||||||
|
awslogs-group = aws_cloudwatch_log_group.main.name
|
||||||
|
awslogs-region = data.aws_region.current.name
|
||||||
|
awslogs-stream-prefix = "${local.full_name}-deprovisioner"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
environment = concat([
|
||||||
|
{
|
||||||
|
name = "TF_VAR_mysql_secret"
|
||||||
|
value = var.mysql_secret.id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "TF_VAR_eks_cluster"
|
||||||
|
value = var.eks_cluster.eks_cluster_id
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
])
|
||||||
|
lifecycle {
|
||||||
|
create_before_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "deprovisioner" {
|
||||||
|
name = "${local.full_name}-deprovisioner"
|
||||||
|
description = "security group for ${local.full_name}-deprovisioner"
|
||||||
|
vpc_id = var.vpc.vpc_id
|
||||||
|
|
||||||
|
egress {
|
||||||
|
description = "egress to all"
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
ipv6_cidr_blocks = ["::/0"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resource "aws_sfn_state_machine" "main" {
|
||||||
|
name = var.prefix
|
||||||
|
role_arn = aws_iam_role.sfn.arn
|
||||||
|
|
||||||
|
definition = <<EOF
|
||||||
|
{
|
||||||
|
"Comment": "Controls the lifecycle of a Fleet demo environment",
|
||||||
|
"StartAt": "Wait",
|
||||||
|
"States": {
|
||||||
|
"Wait": {
|
||||||
|
"Type": "Wait",
|
||||||
|
"SecondsPath": "$.waitTime",
|
||||||
|
"Next": "Deprovisioner"
|
||||||
|
},
|
||||||
|
"Deprovisioner": {
|
||||||
|
"Type": "Task",
|
||||||
|
"Resource": "arn:aws:states:::ecs:runTask.sync",
|
||||||
|
"Parameters": {
|
||||||
|
"LaunchType": "FARGATE",
|
||||||
|
"NetworkConfiguration": {
|
||||||
|
"AwsvpcConfiguration": {
|
||||||
|
"Subnets": ${jsonencode(var.vpc.private_subnets)},
|
||||||
|
"SecurityGroups": ["${aws_security_group.deprovisioner.id}"],
|
||||||
|
"AssignPublicIp": "DISABLED"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Cluster": "${var.ecs_cluster.arn}",
|
||||||
|
"TaskDefinition": "${replace(aws_ecs_task_definition.deprovisioner.arn, "/:\\d+$/", "")}",
|
||||||
|
"Overrides": {
|
||||||
|
"ContainerOverrides": [
|
||||||
|
{
|
||||||
|
"Name": "${var.prefix}-deprovisioner",
|
||||||
|
"Environment": [
|
||||||
|
{
|
||||||
|
"Name": "INSTANCE_ID",
|
||||||
|
"Value.$": "$.instanceID"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"End": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
output "deprovisioner" {
|
||||||
|
value = aws_sfn_state_machine.main
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "random_uuid" "deprovisioner" {
|
||||||
|
keepers = {
|
||||||
|
lambda = data.archive_file.deprovisioner.output_sha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "local_file" "backend-config" {
|
||||||
|
content = templatefile("${path.module}/deprovisioner/backend-template.conf",
|
||||||
|
{
|
||||||
|
remote_state = var.remote_state
|
||||||
|
})
|
||||||
|
filename = "${path.module}/deprovisioner/deploy_terraform/backend.conf"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "archive_file" "deprovisioner" {
|
||||||
|
type = "zip"
|
||||||
|
output_path = "${path.module}/.deprovisioner.zip"
|
||||||
|
source_dir = "${path.module}/deprovisioner"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "docker_registry_image" "deprovisioner" {
|
||||||
|
name = "${aws_ecr_repository.main.repository_url}:${data.git_repository.main.branch}-${random_uuid.deprovisioner.result}"
|
||||||
|
keep_remotely = true
|
||||||
|
|
||||||
|
build {
|
||||||
|
context = "${path.module}/deprovisioner/"
|
||||||
|
pull_parent = true
|
||||||
|
}
|
||||||
|
|
||||||
|
depends_on = [
|
||||||
|
local_file.backend-config
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
output "deprovisioner_role" {
|
||||||
|
value = aws_iam_role.deprovisioner
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
FROM golang:1.18-alpine AS builder
|
||||||
|
RUN apk update && apk add --no-cache git curl openssl unzip
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . .
|
||||||
|
RUN go get -d -v
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-extldflags '-static'"
|
||||||
|
RUN curl https://releases.hashicorp.com/terraform/1.1.8/terraform_1.1.8_linux_amd64.zip > terraform.zip
|
||||||
|
RUN unzip terraform.zip
|
||||||
|
RUN rm terraform.zip
|
||||||
|
RUN chmod 644 $(find . -type f)
|
||||||
|
RUN chmod 755 $(find . -type d)
|
||||||
|
RUN chmod 655 lambda terraform
|
||||||
|
|
||||||
|
#FROM scratch
|
||||||
|
#COPY --from=builder /build/lambda /build/terraform /
|
||||||
|
#COPY --from=builder /build/deploy_terraform /deploy_terraform
|
||||||
|
#COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
|
ENTRYPOINT ["/build/lambda"]
|
@ -0,0 +1,6 @@
|
|||||||
|
bucket = "${remote_state.state_bucket.id}"
|
||||||
|
key = "terraform.tfstate" # This should be set to account_alias/unique_key/terraform.tfstate
|
||||||
|
region = "us-east-2"
|
||||||
|
encrypt = true
|
||||||
|
kms_key_id = "${remote_state.kms_key.id}"
|
||||||
|
dynamodb_table = "${remote_state.dynamodb_table.id}"
|
1
infrastructure/sandbox/JITProvisioner/deprovisioner/deploy_terraform/.gitignore
vendored
Normal file
1
infrastructure/sandbox/JITProvisioner/deprovisioner/deploy_terraform/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
backend.conf
|
@ -0,0 +1,50 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
aws = {
|
||||||
|
source = "hashicorp/aws"
|
||||||
|
version = "~> 4.10.0"
|
||||||
|
}
|
||||||
|
random = {
|
||||||
|
source = "hashicorp/random"
|
||||||
|
version = "~> 3.1.2"
|
||||||
|
}
|
||||||
|
mysql = {
|
||||||
|
source = "petoju/mysql"
|
||||||
|
version = "3.0.12"
|
||||||
|
}
|
||||||
|
helm = {
|
||||||
|
source = "hashicorp/helm"
|
||||||
|
version = "2.5.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backend "s3" {}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "helm" {
|
||||||
|
kubernetes {
|
||||||
|
host = data.aws_eks_cluster.cluster.endpoint
|
||||||
|
token = data.aws_eks_cluster_auth.cluster.token
|
||||||
|
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_eks_cluster" "cluster" {
|
||||||
|
name = var.eks_cluster
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_eks_cluster_auth" "cluster" {
|
||||||
|
name = var.eks_cluster
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "mysql" {
|
||||||
|
endpoint = jsondecode(data.aws_secretsmanager_secret_version.mysql.secret_string)["endpoint"]
|
||||||
|
username = jsondecode(data.aws_secretsmanager_secret_version.mysql.secret_string)["username"]
|
||||||
|
password = jsondecode(data.aws_secretsmanager_secret_version.mysql.secret_string)["password"]
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "mysql_secret" {}
|
||||||
|
variable "eks_cluster" {}
|
||||||
|
|
||||||
|
data "aws_secretsmanager_secret_version" "mysql" {
|
||||||
|
secret_id = var.mysql_secret
|
||||||
|
}
|
16
infrastructure/sandbox/JITProvisioner/deprovisioner/go.mod
Normal file
16
infrastructure/sandbox/JITProvisioner/deprovisioner/go.mod
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module github.com/fleetdm/fleet/infrastructure/demo/PreProvisioner/lambda
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/aws/aws-lambda-go v1.29.0
|
||||||
|
github.com/aws/aws-sdk-go v1.43.37
|
||||||
|
github.com/google/uuid v1.3.0
|
||||||
|
github.com/jessevdk/go-flags v1.5.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||||
|
)
|
33
infrastructure/sandbox/JITProvisioner/deprovisioner/go.sum
Normal file
33
infrastructure/sandbox/JITProvisioner/deprovisioner/go.sum
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
github.com/aws/aws-lambda-go v1.29.0 h1:u+sfZkvNBUgt0ZkO8Q/jOMBV22DqMDMbZu04oomM2no=
|
||||||
|
github.com/aws/aws-lambda-go v1.29.0/go.mod h1:aakqVz9vDHhtbt0U2zegh/z9SI2+rJ+yRREZYNQLmWY=
|
||||||
|
github.com/aws/aws-sdk-go v1.43.37 h1:kyZ7UjaPZaCik+asF33UFOOYSwr9liDRr/UM/vuw8yY=
|
||||||
|
github.com/aws/aws-sdk-go v1.43.37/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
|
||||||
|
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
92
infrastructure/sandbox/JITProvisioner/deprovisioner/main.go
Normal file
92
infrastructure/sandbox/JITProvisioner/deprovisioner/main.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/aws/aws-lambda-go/lambda"
|
||||||
|
flags "github.com/jessevdk/go-flags"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OptionsStruct struct {
|
||||||
|
LambdaExecutionEnv string `long:"lambda-execution-environment" env:"AWS_EXECUTION_ENV"`
|
||||||
|
InstanceID string `long:"instance-id" env:"INSTANCE_ID" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = OptionsStruct{}
|
||||||
|
|
||||||
|
type LifecycleRecord struct {
|
||||||
|
ID string
|
||||||
|
State string
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCmd(args []string) error {
|
||||||
|
cmd := exec.Cmd{
|
||||||
|
Path: "/build/terraform",
|
||||||
|
Dir: "/build/deploy_terraform",
|
||||||
|
Stdout: os.Stdout,
|
||||||
|
Stderr: os.Stderr,
|
||||||
|
Args: append([]string{"/build/terraform"}, args...),
|
||||||
|
}
|
||||||
|
log.Printf("%+v\n", cmd)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func initTerraform() error {
|
||||||
|
err := runCmd([]string{
|
||||||
|
"init",
|
||||||
|
"-backend-config=backend.conf",
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTerraform(workspace string) error {
|
||||||
|
err := runCmd([]string{
|
||||||
|
"workspace",
|
||||||
|
"select",
|
||||||
|
workspace,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = runCmd([]string{
|
||||||
|
"destroy",
|
||||||
|
"-auto-approve",
|
||||||
|
"-no-color",
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func handler(ctx context.Context, name NullEvent) error {
|
||||||
|
if err := initTerraform(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := runTerraform(options.InstanceID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullEvent struct{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
// Get config from environment
|
||||||
|
parser := flags.NewParser(&options, flags.Default)
|
||||||
|
if _, err = parser.Parse(); err != nil {
|
||||||
|
if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if options.LambdaExecutionEnv == "AWS_Lambda_go1.x" {
|
||||||
|
lambda.Start(handler)
|
||||||
|
} else {
|
||||||
|
if err = handler(context.Background(), NullEvent{}); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
174
infrastructure/sandbox/JITProvisioner/jitprovisioner.tf
Normal file
174
infrastructure/sandbox/JITProvisioner/jitprovisioner.tf
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
resource "aws_lb_listener_rule" "jitprovisioner" {
|
||||||
|
listener_arn = var.alb_listener.arn
|
||||||
|
priority = 100
|
||||||
|
|
||||||
|
action {
|
||||||
|
type = "forward"
|
||||||
|
target_group_arn = aws_lb_target_group.jitprovisioner.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
condition {
|
||||||
|
host_header {
|
||||||
|
values = [var.base_domain]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lb_target_group_attachment" "jitprovisioner" {
|
||||||
|
target_group_arn = aws_lb_target_group.jitprovisioner.arn
|
||||||
|
target_id = aws_lambda_function.jitprovisioner.arn
|
||||||
|
depends_on = [aws_lambda_permission.jitprovisioner]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lambda_permission" "jitprovisioner" {
|
||||||
|
action = "lambda:InvokeFunction"
|
||||||
|
function_name = aws_lambda_function.jitprovisioner.arn
|
||||||
|
principal = "elasticloadbalancing.amazonaws.com"
|
||||||
|
source_arn = aws_lb_target_group.jitprovisioner.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lb_target_group" "jitprovisioner" {
|
||||||
|
name = "${local.full_name}-lambda"
|
||||||
|
target_type = "lambda"
|
||||||
|
lambda_multi_value_headers_enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "lambda_assume_role" {
|
||||||
|
statement {
|
||||||
|
actions = ["sts:AssumeRole"]
|
||||||
|
principals {
|
||||||
|
type = "Service"
|
||||||
|
identifiers = ["lambda.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role" "jitprovisioner" {
|
||||||
|
name = "${var.prefix}-lambda"
|
||||||
|
assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "jitprovisioner-ecr" {
|
||||||
|
role = aws_iam_role.jitprovisioner.name
|
||||||
|
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "jitprovisioner-vpc" {
|
||||||
|
role = aws_iam_role.jitprovisioner.name
|
||||||
|
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_policy" "jitprovisioner" {
|
||||||
|
name = "${var.prefix}-jitprovisioner"
|
||||||
|
policy = data.aws_iam_policy_document.jitprovisioner.json
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "jitprovisioner" {
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"dynamodb:BatchGetItem",
|
||||||
|
"dynamodb:BatchWriteItem",
|
||||||
|
"dynamodb:ConditionCheckItem",
|
||||||
|
"dynamodb:PutItem",
|
||||||
|
"dynamodb:DescribeTable",
|
||||||
|
"dynamodb:DeleteItem",
|
||||||
|
"dynamodb:GetItem",
|
||||||
|
"dynamodb:Scan",
|
||||||
|
"dynamodb:Query",
|
||||||
|
"dynamodb:UpdateItem",
|
||||||
|
]
|
||||||
|
resources = [var.dynamodb_table.arn, "${var.dynamodb_table.arn}/*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = [ #tfsec:ignore:aws-iam-no-policy-wildcards
|
||||||
|
"kms:Encrypt*",
|
||||||
|
"kms:Decrypt*",
|
||||||
|
"kms:ReEncrypt*",
|
||||||
|
"kms:GenerateDataKey*",
|
||||||
|
"kms:Describe*"
|
||||||
|
]
|
||||||
|
resources = [var.kms_key.arn]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = ["states:StartExecution"]
|
||||||
|
resources = [aws_sfn_state_machine.main.arn]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = ["states:DescribeExecution"]
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "jitprovisioner" {
|
||||||
|
role = aws_iam_role.jitprovisioner.name
|
||||||
|
policy_arn = aws_iam_policy.jitprovisioner.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lambda_function" "jitprovisioner" {
|
||||||
|
# If the file is not in the current working directory you will need to include a
|
||||||
|
# path.module in the filename.
|
||||||
|
image_uri = docker_registry_image.jitprovisioner.name
|
||||||
|
package_type = "Image"
|
||||||
|
function_name = "${var.prefix}-lambda"
|
||||||
|
role = aws_iam_role.jitprovisioner.arn
|
||||||
|
reserved_concurrent_executions = -1
|
||||||
|
kms_key_arn = var.kms_key.arn
|
||||||
|
timeout = 10
|
||||||
|
memory_size = 512
|
||||||
|
vpc_config {
|
||||||
|
security_group_ids = [aws_security_group.jitprovisioner.id]
|
||||||
|
subnet_ids = var.vpc.private_subnets
|
||||||
|
}
|
||||||
|
tracing_config {
|
||||||
|
mode = "Active"
|
||||||
|
}
|
||||||
|
environment {
|
||||||
|
variables = {
|
||||||
|
DYNAMODB_LIFECYCLE_TABLE = var.dynamodb_table.id
|
||||||
|
LIFECYCLE_SFN = aws_sfn_state_machine.main.arn
|
||||||
|
FLEET_BASE_URL = "${var.base_domain}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "jitprovisioner" {
|
||||||
|
value = aws_lambda_function.jitprovisioner
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "random_uuid" "jitprovisioner" {
|
||||||
|
keepers = {
|
||||||
|
lambda = data.archive_file.jitprovisioner.output_sha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "archive_file" "jitprovisioner" {
|
||||||
|
type = "zip"
|
||||||
|
output_path = "${path.module}/.jitprovisioner.zip"
|
||||||
|
source_dir = "${path.module}/lambda"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "docker_registry_image" "jitprovisioner" {
|
||||||
|
name = "${aws_ecr_repository.main.repository_url}:${data.git_repository.main.branch}-${random_uuid.jitprovisioner.result}"
|
||||||
|
keep_remotely = true
|
||||||
|
|
||||||
|
build {
|
||||||
|
context = "${path.module}/lambda/"
|
||||||
|
pull_parent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "jitprovisioner" {
|
||||||
|
name = local.full_name
|
||||||
|
vpc_id = var.vpc.vpc_id
|
||||||
|
description = local.full_name
|
||||||
|
egress {
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
ipv6_cidr_blocks = ["::/0"]
|
||||||
|
}
|
||||||
|
}
|
1
infrastructure/sandbox/JITProvisioner/lambda/.gitignore
vendored
Normal file
1
infrastructure/sandbox/JITProvisioner/lambda/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
lambda
|
11
infrastructure/sandbox/JITProvisioner/lambda/Dockerfile
Normal file
11
infrastructure/sandbox/JITProvisioner/lambda/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM golang:1.18-alpine AS builder
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . .
|
||||||
|
RUN go get -d -v
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-extldflags '-static'"
|
||||||
|
|
||||||
|
#FROM scratch
|
||||||
|
#COPY --from=builder /build/lambda /build/terraform /
|
||||||
|
#COPY --from=builder /build/deploy_terraform /deploy_terraform
|
||||||
|
#COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
|
ENTRYPOINT ["/build/lambda"]
|
116
infrastructure/sandbox/JITProvisioner/lambda/go.mod
Normal file
116
infrastructure/sandbox/JITProvisioner/lambda/go.mod
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
module github.com/fleetdm/fleet/infrastructure/demo/JITProvisioner/lambda
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/akrylysov/algnhsa v0.12.1
|
||||||
|
github.com/aws/aws-sdk-go v1.44.25
|
||||||
|
github.com/fleetdm/fleet/v4 v4.1.0
|
||||||
|
github.com/gin-gonic/gin v1.7.7
|
||||||
|
github.com/jessevdk/go-flags v1.5.0
|
||||||
|
github.com/loopfz/gadgeto v0.11.2
|
||||||
|
github.com/wI2L/fizz v0.20.0
|
||||||
|
go.elastic.co/apm/module/apmgin/v2 v2.1.0
|
||||||
|
go.elastic.co/apm/v2 v2.1.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
cloud.google.com/go v0.81.0 // indirect
|
||||||
|
cloud.google.com/go/pubsub v1.5.0 // indirect
|
||||||
|
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||||
|
github.com/WatchBeam/clock v0.0.0-20170901150240-b08e6b4da7ea // indirect
|
||||||
|
github.com/armon/go-radix v1.0.0 // indirect
|
||||||
|
github.com/aws/aws-lambda-go v1.31.1 // indirect
|
||||||
|
github.com/beevik/etree v1.1.0 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/elastic/go-licenser v0.4.0 // indirect
|
||||||
|
github.com/elastic/go-sysinfo v1.7.1 // indirect
|
||||||
|
github.com/elastic/go-windows v1.0.1 // indirect
|
||||||
|
github.com/elazarl/go-bindata-assetfs v1.0.0 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-kit/kit v0.9.0 // indirect
|
||||||
|
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.0 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.9.0 // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||||
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
|
github.com/gofrs/uuid v3.2.0+incompatible // indirect
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/gomodule/redigo v1.8.4 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.5 // indirect
|
||||||
|
github.com/google/uuid v1.1.2 // indirect
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
||||||
|
github.com/gorilla/mux v1.8.0 // indirect
|
||||||
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/igm/sockjs-go/v3 v3.0.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/jcchavezs/porto v0.1.0 // indirect
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect
|
||||||
|
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/jstemmer/go-junit-report v0.9.1 // indirect
|
||||||
|
github.com/kolide/kit v0.0.0-20180421083548-36eb8dc43916 // indirect
|
||||||
|
github.com/leodido/go-urn v1.2.1 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.5 // indirect
|
||||||
|
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201213122252-bcd7e1b9601e // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
|
github.com/mna/redisc v1.2.1 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/open-policy-agent/opa v0.24.0 // indirect
|
||||||
|
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/prometheus/client_golang v0.9.3 // indirect
|
||||||
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
|
github.com/prometheus/common v0.4.1 // indirect
|
||||||
|
github.com/prometheus/procfs v0.7.3 // indirect
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
|
||||||
|
github.com/russellhaering/goxmldsig v1.1.0 // indirect
|
||||||
|
github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect
|
||||||
|
github.com/spf13/afero v1.6.0 // indirect
|
||||||
|
github.com/spf13/cast v1.3.1 // indirect
|
||||||
|
github.com/spf13/cobra v0.0.6 // indirect
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/spf13/viper v1.8.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.7.0 // indirect
|
||||||
|
github.com/subosito/gotenv v1.2.0 // indirect
|
||||||
|
github.com/throttled/throttled/v2 v2.8.0 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.6 // indirect
|
||||||
|
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b // indirect
|
||||||
|
go.elastic.co/apm/module/apmhttp/v2 v2.1.0 // indirect
|
||||||
|
go.elastic.co/fastjson v1.1.0 // indirect
|
||||||
|
go.opencensus.io v0.23.0 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
|
||||||
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
||||||
|
golang.org/x/mod v0.5.1 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 // indirect
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect
|
||||||
|
golang.org/x/text v0.3.7 // indirect
|
||||||
|
golang.org/x/tools v0.1.9 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
|
google.golang.org/api v0.44.0 // indirect
|
||||||
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||||
|
google.golang.org/grpc v1.38.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
|
gopkg.in/guregu/null.v3 v3.4.0 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0-20170531160350-a96e63847dc3 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
|
howett.net/plist v1.0.0 // indirect
|
||||||
|
)
|
1079
infrastructure/sandbox/JITProvisioner/lambda/go.sum
Normal file
1079
infrastructure/sandbox/JITProvisioner/lambda/go.sum
Normal file
File diff suppressed because it is too large
Load Diff
259
infrastructure/sandbox/JITProvisioner/lambda/main.go
Normal file
259
infrastructure/sandbox/JITProvisioner/lambda/main.go
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/akrylysov/algnhsa"
|
||||||
|
//"github.com/gin-contrib/cors" TODO: use cors
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
flags "github.com/jessevdk/go-flags"
|
||||||
|
//"github.com/juju/errors"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/arn"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||||
|
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sfn"
|
||||||
|
"github.com/fleetdm/fleet/v4/server/service"
|
||||||
|
"github.com/loopfz/gadgeto/tonic"
|
||||||
|
"github.com/wI2L/fizz"
|
||||||
|
"github.com/wI2L/fizz/openapi"
|
||||||
|
"go.elastic.co/apm/module/apmgin/v2"
|
||||||
|
_ "go.elastic.co/apm/v2"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OptionsStruct struct {
|
||||||
|
LambdaExecutionEnv string `long:"lambda-execution-environment" env:"AWS_EXECUTION_ENV"`
|
||||||
|
LifecycleTable string `long:"dynamodb-lifecycle-table" env:"DYNAMODB_LIFECYCLE_TABLE" required:"true"`
|
||||||
|
LifecycleSFN string `long:"lifecycle-sfn" env:"LIFECYCLE_SFN" required:"true"`
|
||||||
|
FleetBaseURL string `long:"fleet-base-url" env:"FLEET_BASE_URL" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = OptionsStruct{}
|
||||||
|
|
||||||
|
type LifecycleRecord struct {
|
||||||
|
ID string
|
||||||
|
State string
|
||||||
|
RedisDB int `dynamodbav:"redis_db"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExpiry(id string) (ret time.Time, err error) {
|
||||||
|
var execArn arn.ARN
|
||||||
|
var exec *sfn.DescribeExecutionOutput
|
||||||
|
var input struct {
|
||||||
|
WaitTime int `json:"waitTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
execArn, err = arn.Parse(options.LifecycleSFN)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
execArn.Resource = fmt.Sprintf("execution:%s:%s", strings.Split(execArn.Resource, ":")[1], id)
|
||||||
|
|
||||||
|
exec, err = sfn.New(session.New()).DescribeExecution(&sfn.DescribeExecutionInput{
|
||||||
|
ExecutionArn: aws.String(execArn.String()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.Unmarshal([]byte(*exec.Input), &input); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var dur time.Duration
|
||||||
|
if dur, err = time.ParseDuration(fmt.Sprintf("%ds", input.WaitTime)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret = exec.StartDate.Add(dur)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func claimFleet(fleet LifecycleRecord, svc *dynamodb.DynamoDB) (err error) {
|
||||||
|
log.Printf("Claiming instance: %+v", fleet)
|
||||||
|
// Perform a conditional update to claim the item
|
||||||
|
input := &dynamodb.UpdateItemInput{
|
||||||
|
ConditionExpression: aws.String("#fleet_state = :v1"),
|
||||||
|
TableName: aws.String(options.LifecycleTable),
|
||||||
|
Key: map[string]*dynamodb.AttributeValue{
|
||||||
|
"ID": {
|
||||||
|
S: aws.String(fleet.ID),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
UpdateExpression: aws.String("set #fleet_state = :v2"),
|
||||||
|
ExpressionAttributeNames: map[string]*string{"#fleet_state": aws.String("State")},
|
||||||
|
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
|
||||||
|
":v1": {
|
||||||
|
S: aws.String("unclaimed"),
|
||||||
|
},
|
||||||
|
":v2": {
|
||||||
|
S: aws.String("claimed"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if _, err = svc.UpdateItem(input); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFleetInstance() (ret LifecycleRecord, err error) {
|
||||||
|
log.Print("Getting fleet instance")
|
||||||
|
svc := dynamodb.New(session.New())
|
||||||
|
// Loop until we get one
|
||||||
|
for {
|
||||||
|
input := &dynamodb.QueryInput{
|
||||||
|
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
|
||||||
|
":v1": {
|
||||||
|
S: aws.String("unclaimed"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
KeyConditionExpression: aws.String("#fleet_state = :v1"),
|
||||||
|
TableName: aws.String(options.LifecycleTable),
|
||||||
|
ExpressionAttributeNames: map[string]*string{"#fleet_state": aws.String("State")},
|
||||||
|
IndexName: aws.String("FleetState"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var result *dynamodb.QueryOutput
|
||||||
|
if result, err = svc.Query(input); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
recs := []LifecycleRecord{}
|
||||||
|
if err = dynamodbattribute.UnmarshalListOfMaps(result.Items, &recs); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret = recs[rand.Intn(len(recs))]
|
||||||
|
if err = claimFleet(ret, svc); err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func triggerSFN(id, expiry string) (err error) {
|
||||||
|
var endTime time.Time
|
||||||
|
log.Print("Triggering state machine")
|
||||||
|
if endTime, err = time.Parse(time.RFC3339, expiry); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if int(endTime.Sub(time.Now()).Seconds()) < 0 {
|
||||||
|
return errors.New("Expiry time is in the past")
|
||||||
|
}
|
||||||
|
sfnInStr, err := json.Marshal(struct {
|
||||||
|
InstanceID string `json:"instanceID"`
|
||||||
|
WaitTime int `json:"waitTime"`
|
||||||
|
}{
|
||||||
|
InstanceID: id,
|
||||||
|
WaitTime: int(endTime.Sub(time.Now()).Seconds()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sfnIn := sfn.StartExecutionInput{
|
||||||
|
Input: aws.String(string(sfnInStr)),
|
||||||
|
Name: aws.String(id),
|
||||||
|
StateMachineArn: aws.String(options.LifecycleSFN),
|
||||||
|
}
|
||||||
|
_, err = sfn.New(session.New()).StartExecution(&sfnIn)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type HealthInput struct{}
|
||||||
|
type HealthOutput struct {
|
||||||
|
Message string `json:"message" description:"The status of the API." example:"The API is healthy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Health(c *gin.Context, in *HealthInput) (ret *HealthOutput, err error) {
|
||||||
|
ret = &HealthOutput{
|
||||||
|
Message: "Healthy",
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type NewFleetInput struct {
|
||||||
|
Email string `json:"email" validate:"required,email"`
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
SandboxExpiration string `json:"sandbox_expiration" validate:"required"`
|
||||||
|
Password string `json:"password" validate:"required"`
|
||||||
|
}
|
||||||
|
type NewFleetOutput struct {
|
||||||
|
URL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFleet(c *gin.Context, in *NewFleetInput) (ret *NewFleetOutput, err error) {
|
||||||
|
ret = &NewFleetOutput{}
|
||||||
|
fleet, err := getFleetInstance()
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Print("Creating fleet client")
|
||||||
|
ret.URL = fmt.Sprintf("https://%s.%s", fleet.ID, options.FleetBaseURL)
|
||||||
|
log.Print(ret.URL)
|
||||||
|
client, err := service.NewClient(ret.URL, true, "", "")
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Print("Creating admin user")
|
||||||
|
if _, err = client.Setup(in.Email, in.Name, in.Password, fleet.ID); err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = triggerSFN(fleet.ID, in.SandboxExpiration); err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExpiryInput struct {
|
||||||
|
ID string `query:"id" validate:"required"`
|
||||||
|
}
|
||||||
|
type ExpiryOutput struct {
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetExpiry(c *gin.Context, in *ExpiryInput) (ret *ExpiryOutput, err error) {
|
||||||
|
ret = &ExpiryOutput{}
|
||||||
|
var expiry time.Time
|
||||||
|
if expiry, err = getExpiry(in.ID); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ret.Timestamp = expiry.Format(time.RFC3339)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
var err error
|
||||||
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
// Get config from environment
|
||||||
|
parser := flags.NewParser(&options, flags.Default)
|
||||||
|
if _, err = parser.Parse(); err != nil {
|
||||||
|
if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r := gin.Default()
|
||||||
|
r.Use(apmgin.Middleware(r))
|
||||||
|
f := fizz.NewFromEngine(r)
|
||||||
|
infos := &openapi.Info{
|
||||||
|
Title: "Fleet Demo JITProvisioner",
|
||||||
|
Description: "Provisions new Fleet instances upon request",
|
||||||
|
Version: "1.0.0",
|
||||||
|
}
|
||||||
|
f.GET("/openapi.json", nil, f.OpenAPI(infos, "json"))
|
||||||
|
f.GET("/health", nil, tonic.Handler(Health, 200))
|
||||||
|
f.POST("/new", nil, tonic.Handler(NewFleet, 200))
|
||||||
|
f.GET("/expires", nil, tonic.Handler(GetExpiry, 200))
|
||||||
|
algnhsa.ListenAndServe(r, nil)
|
||||||
|
}
|
48
infrastructure/sandbox/JITProvisioner/main.tf
Normal file
48
infrastructure/sandbox/JITProvisioner/main.tf
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
docker = {
|
||||||
|
source = "kreuzwerker/docker"
|
||||||
|
version = "~> 2.16.0"
|
||||||
|
}
|
||||||
|
git = {
|
||||||
|
source = "paultyng/git"
|
||||||
|
version = "~> 0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_region" "current" {}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
name = "jit"
|
||||||
|
full_name = "${var.prefix}-${local.name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_log_group" "main" {
|
||||||
|
name = local.full_name
|
||||||
|
kms_key_id = var.kms_key.arn
|
||||||
|
retention_in_days = 30
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_kms_key" "ecr" {
|
||||||
|
deletion_window_in_days = 10
|
||||||
|
enable_key_rotation = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_ecr_repository" "main" {
|
||||||
|
name = var.prefix
|
||||||
|
image_tag_mutability = "IMMUTABLE"
|
||||||
|
|
||||||
|
image_scanning_configuration {
|
||||||
|
scan_on_push = true
|
||||||
|
}
|
||||||
|
|
||||||
|
encryption_configuration {
|
||||||
|
encryption_type = "KMS"
|
||||||
|
kms_key = aws_kms_key.ecr.arn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "git_repository" "main" {
|
||||||
|
path = "${path.module}/../../../"
|
||||||
|
}
|
11
infrastructure/sandbox/JITProvisioner/variables.tf
Normal file
11
infrastructure/sandbox/JITProvisioner/variables.tf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
variable "prefix" {}
|
||||||
|
variable "dynamodb_table" {}
|
||||||
|
variable "vpc" {}
|
||||||
|
variable "remote_state" {}
|
||||||
|
variable "mysql_secret" {}
|
||||||
|
variable "eks_cluster" {}
|
||||||
|
variable "redis_cluster" {}
|
||||||
|
variable "alb_listener" {}
|
||||||
|
variable "base_domain" {}
|
||||||
|
variable "ecs_cluster" {}
|
||||||
|
variable "kms_key" {}
|
1
infrastructure/sandbox/Monitoring/.gitignore
vendored
Normal file
1
infrastructure/sandbox/Monitoring/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.lambda.zip
|
11
infrastructure/sandbox/Monitoring/lambda/Dockerfile
Normal file
11
infrastructure/sandbox/Monitoring/lambda/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM golang:1.18-alpine AS builder
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . .
|
||||||
|
RUN go get -d -v
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-extldflags '-static'"
|
||||||
|
|
||||||
|
#FROM scratch
|
||||||
|
#COPY --from=builder /build/lambda /build/terraform /
|
||||||
|
#COPY --from=builder /build/deploy_terraform /deploy_terraform
|
||||||
|
#COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
|
ENTRYPOINT ["/build/lambda"]
|
14
infrastructure/sandbox/Monitoring/lambda/go.mod
Normal file
14
infrastructure/sandbox/Monitoring/lambda/go.mod
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module github.com/fleetdm/fleet/infrastructure/demo/Monitoring/lambda
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/aws/aws-lambda-go v1.32.1
|
||||||
|
github.com/aws/aws-sdk-go v1.44.50
|
||||||
|
github.com/jessevdk/go-flags v1.5.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||||
|
)
|
29
infrastructure/sandbox/Monitoring/lambda/go.sum
Normal file
29
infrastructure/sandbox/Monitoring/lambda/go.sum
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
github.com/aws/aws-lambda-go v1.32.1 h1:ls0FU8Mt7ayJszb945zFkUfzxhkQTli8mpJstVcDtCY=
|
||||||
|
github.com/aws/aws-lambda-go v1.32.1/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM=
|
||||||
|
github.com/aws/aws-sdk-go v1.44.50 h1:dg6nbI+4734bTj1Q6FCQqiIiE+lb8HpGQJqZEvZeMrY=
|
||||||
|
github.com/aws/aws-sdk-go v1.44.50/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
|
||||||
|
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||||
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
114
infrastructure/sandbox/Monitoring/lambda/main.go
Normal file
114
infrastructure/sandbox/Monitoring/lambda/main.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/aws/aws-lambda-go/lambda"
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||||
|
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||||
|
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
|
||||||
|
flags "github.com/jessevdk/go-flags"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OptionsStruct struct {
|
||||||
|
LambdaExecutionEnv string `long:"lambda-execution-environment" env:"AWS_EXECUTION_ENV"`
|
||||||
|
LifecycleTable string `long:"dynamodb-lifecycle-table" env:"DYNAMODB_LIFECYCLE_TABLE" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = OptionsStruct{}
|
||||||
|
|
||||||
|
type LifecycleRecord struct {
|
||||||
|
State string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInstancesCount() (int64, int64, error) {
|
||||||
|
log.Print("getInstancesCount")
|
||||||
|
svc := dynamodb.New(session.New())
|
||||||
|
// Example iterating over at most 3 pages of a Scan operation.
|
||||||
|
var count, unclaimedCount int64
|
||||||
|
err := svc.ScanPages(
|
||||||
|
&dynamodb.ScanInput{
|
||||||
|
TableName: aws.String(options.LifecycleTable),
|
||||||
|
},
|
||||||
|
func(page *dynamodb.ScanOutput, lastPage bool) bool {
|
||||||
|
count += *page.Count
|
||||||
|
recs := []LifecycleRecord{}
|
||||||
|
if err := dynamodbattribute.UnmarshalListOfMaps(page.Items, &recs); err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, i := range recs {
|
||||||
|
if i.State == "unclaimed" {
|
||||||
|
unclaimedCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
return count, unclaimedCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullEvent struct{}
|
||||||
|
|
||||||
|
func handler(ctx context.Context, name NullEvent) error {
|
||||||
|
totalCount, unclaimedCount, err := getInstancesCount()
|
||||||
|
svc := cloudwatch.New(session.New())
|
||||||
|
log.Printf("Publishing %d, %d", totalCount, unclaimedCount)
|
||||||
|
_, err = svc.PutMetricData(&cloudwatch.PutMetricDataInput{
|
||||||
|
Namespace: aws.String("Fleet/sandbox"),
|
||||||
|
MetricData: []*cloudwatch.MetricDatum{
|
||||||
|
&cloudwatch.MetricDatum{
|
||||||
|
Dimensions: []*cloudwatch.Dimension{
|
||||||
|
&cloudwatch.Dimension{
|
||||||
|
Name: aws.String("Type"),
|
||||||
|
Value: aws.String("totalCount"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MetricName: aws.String("instances"),
|
||||||
|
Value: aws.Float64(float64(totalCount)),
|
||||||
|
Unit: aws.String(cloudwatch.StandardUnitCount),
|
||||||
|
},
|
||||||
|
&cloudwatch.MetricDatum{
|
||||||
|
Dimensions: []*cloudwatch.Dimension{
|
||||||
|
&cloudwatch.Dimension{
|
||||||
|
Name: aws.String("Type"),
|
||||||
|
Value: aws.String("unclaimedCount"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MetricName: aws.String("instances"),
|
||||||
|
Value: aws.Float64(float64(unclaimedCount)),
|
||||||
|
Unit: aws.String(cloudwatch.StandardUnitCount),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
// Get config from environment
|
||||||
|
parser := flags.NewParser(&options, flags.Default)
|
||||||
|
if _, err = parser.Parse(); err != nil {
|
||||||
|
if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if options.LambdaExecutionEnv == "AWS_Lambda_go1.x" {
|
||||||
|
lambda.Start(handler)
|
||||||
|
} else {
|
||||||
|
if err = handler(context.Background(), NullEvent{}); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
279
infrastructure/sandbox/Monitoring/main.tf
Normal file
279
infrastructure/sandbox/Monitoring/main.tf
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
docker = {
|
||||||
|
source = "kreuzwerker/docker"
|
||||||
|
version = "~> 2.16.0"
|
||||||
|
}
|
||||||
|
git = {
|
||||||
|
source = "paultyng/git"
|
||||||
|
version = "~> 0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_region" "current" {}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
full_name = "${var.prefix}-monitoring"
|
||||||
|
}
|
||||||
|
|
||||||
|
module "notify_slack" {
|
||||||
|
source = "terraform-aws-modules/notify-slack/aws"
|
||||||
|
version = "~> 4.0"
|
||||||
|
|
||||||
|
sns_topic_name = var.prefix
|
||||||
|
|
||||||
|
slack_webhook_url = var.slack_webhook
|
||||||
|
slack_channel = "#g-infrastructure"
|
||||||
|
slack_username = "monitoring"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "lifecycle-lambda-assume-role" {
|
||||||
|
statement {
|
||||||
|
actions = ["sts:AssumeRole"]
|
||||||
|
principals {
|
||||||
|
type = "Service"
|
||||||
|
identifiers = ["lambda.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "lifecycle-lambda-lambda" {
|
||||||
|
role = aws_iam_role.lifecycle-lambda.id
|
||||||
|
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "lifecycle-lambda" {
|
||||||
|
role = aws_iam_role.lifecycle-lambda.id
|
||||||
|
policy_arn = aws_iam_policy.lifecycle-lambda.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_policy" "lifecycle-lambda" {
|
||||||
|
name = "${local.full_name}-lifecycle-lambda"
|
||||||
|
policy = data.aws_iam_policy_document.lifecycle-lambda.json
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "lifecycle-lambda" {
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"dynamodb:List*",
|
||||||
|
"dynamodb:DescribeReservedCapacity*",
|
||||||
|
"dynamodb:DescribeLimits",
|
||||||
|
"dynamodb:DescribeTimeToLive"
|
||||||
|
]
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"dynamodb:BatchGet*",
|
||||||
|
"dynamodb:DescribeStream",
|
||||||
|
"dynamodb:DescribeTable",
|
||||||
|
"dynamodb:Get*",
|
||||||
|
"dynamodb:Query",
|
||||||
|
"dynamodb:Scan",
|
||||||
|
"dynamodb:BatchWrite*",
|
||||||
|
"dynamodb:CreateTable",
|
||||||
|
"dynamodb:Delete*",
|
||||||
|
"dynamodb:Update*",
|
||||||
|
"dynamodb:PutItem"
|
||||||
|
]
|
||||||
|
resources = [var.dynamodb_table.arn]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = [ #tfsec:ignore:aws-iam-no-policy-wildcards
|
||||||
|
"kms:Encrypt*",
|
||||||
|
"kms:Decrypt*",
|
||||||
|
"kms:ReEncrypt*",
|
||||||
|
"kms:GenerateDataKey*",
|
||||||
|
"kms:Describe*"
|
||||||
|
]
|
||||||
|
resources = [aws_kms_key.ecr.arn]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = ["cloudwatch:PutMetricData"]
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role" "lifecycle-lambda" {
|
||||||
|
name = local.full_name
|
||||||
|
|
||||||
|
assume_role_policy = data.aws_iam_policy_document.lifecycle-lambda-assume-role.json
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_kms_key" "ecr" {
|
||||||
|
deletion_window_in_days = 10
|
||||||
|
enable_key_rotation = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_ecr_repository" "main" {
|
||||||
|
name = local.full_name
|
||||||
|
image_tag_mutability = "IMMUTABLE"
|
||||||
|
|
||||||
|
image_scanning_configuration {
|
||||||
|
scan_on_push = true
|
||||||
|
}
|
||||||
|
|
||||||
|
encryption_configuration {
|
||||||
|
encryption_type = "KMS"
|
||||||
|
kms_key = aws_kms_key.ecr.arn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "random_uuid" "lifecycle-lambda" {
|
||||||
|
keepers = {
|
||||||
|
lambda = data.archive_file.lifecycle-lambda.output_sha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "archive_file" "lifecycle-lambda" {
|
||||||
|
type = "zip"
|
||||||
|
output_path = "${path.module}/.lambda.zip"
|
||||||
|
source_dir = "${path.module}/lambda"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "git_repository" "main" {
|
||||||
|
path = "${path.module}/../../../"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "docker_registry_image" "lifecycle-lambda" {
|
||||||
|
name = "${aws_ecr_repository.main.repository_url}:${data.git_repository.main.branch}-${random_uuid.lifecycle-lambda.result}"
|
||||||
|
keep_remotely = true
|
||||||
|
|
||||||
|
build {
|
||||||
|
context = "${path.module}/lambda/"
|
||||||
|
pull_parent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_event_rule" "lifecycle" {
|
||||||
|
name_prefix = local.full_name
|
||||||
|
schedule_expression = "rate(5 minutes)"
|
||||||
|
is_enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_event_target" "lifecycle" {
|
||||||
|
rule = aws_cloudwatch_event_rule.lifecycle.name
|
||||||
|
arn = aws_lambda_function.lifecycle.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lambda_function" "lifecycle" {
|
||||||
|
# If the file is not in the current working directory you will need to include a
|
||||||
|
# path.module in the filename.
|
||||||
|
image_uri = docker_registry_image.lifecycle-lambda.name
|
||||||
|
package_type = "Image"
|
||||||
|
function_name = "${local.full_name}-lifecycle-lambda"
|
||||||
|
kms_key_arn = var.kms_key.arn
|
||||||
|
role = aws_iam_role.lifecycle-lambda.arn
|
||||||
|
reserved_concurrent_executions = -1
|
||||||
|
timeout = 10
|
||||||
|
memory_size = 512
|
||||||
|
tracing_config {
|
||||||
|
mode = "Active"
|
||||||
|
}
|
||||||
|
environment {
|
||||||
|
variables = {
|
||||||
|
DYNAMODB_LIFECYCLE_TABLE = var.dynamodb_table.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lambda_permission" "lifecycle" {
|
||||||
|
action = "lambda:InvokeFunction"
|
||||||
|
function_name = aws_lambda_function.lifecycle.function_name
|
||||||
|
principal = "events.amazonaws.com"
|
||||||
|
source_arn = aws_cloudwatch_event_rule.lifecycle.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_metric_alarm" "totalInstances" {
|
||||||
|
alarm_name = "${var.prefix}-lifecycle-totalCount"
|
||||||
|
comparison_operator = "GreaterThanThreshold"
|
||||||
|
evaluation_periods = "1"
|
||||||
|
metric_name = "instances"
|
||||||
|
namespace = "Fleet/sandbox"
|
||||||
|
period = "900"
|
||||||
|
statistic = "Average"
|
||||||
|
threshold = "90"
|
||||||
|
alarm_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
ok_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
treat_missing_data = "breaching"
|
||||||
|
datapoints_to_alarm = 1
|
||||||
|
dimensions = {
|
||||||
|
Type = "totalCount"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_metric_alarm" "unclaimed" {
|
||||||
|
alarm_name = "${var.prefix}-lifecycle-unclaimed"
|
||||||
|
comparison_operator = "LessThanThreshold"
|
||||||
|
evaluation_periods = "1"
|
||||||
|
metric_name = "instances"
|
||||||
|
namespace = "Fleet/sandbox"
|
||||||
|
period = "900"
|
||||||
|
statistic = "Average"
|
||||||
|
threshold = "10"
|
||||||
|
alarm_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
ok_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
treat_missing_data = "breaching"
|
||||||
|
datapoints_to_alarm = 1
|
||||||
|
dimensions = {
|
||||||
|
Type = "unclaimedCount"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_metric_alarm" "lb" {
|
||||||
|
for_each = toset(["HTTPCode_ELB_5XX_Count", "HTTPCode_Target_5XX_Count"])
|
||||||
|
alarm_name = "${var.prefix}-lb-${each.key}"
|
||||||
|
comparison_operator = "GreaterThanThreshold"
|
||||||
|
evaluation_periods = "1"
|
||||||
|
metric_name = each.key
|
||||||
|
namespace = "AWS/ApplicationELB"
|
||||||
|
period = "120"
|
||||||
|
statistic = "Sum"
|
||||||
|
threshold = "0"
|
||||||
|
alarm_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
ok_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
treat_missing_data = "notBreaching"
|
||||||
|
dimensions = {
|
||||||
|
LoadBalancer = var.lb.arn_suffix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_metric_alarm" "jitprovisioner" {
|
||||||
|
for_each = toset(["Errors"])
|
||||||
|
alarm_name = "${var.prefix}-jitprovisioner-${each.key}"
|
||||||
|
comparison_operator = "GreaterThanThreshold"
|
||||||
|
evaluation_periods = "1"
|
||||||
|
metric_name = each.key
|
||||||
|
namespace = "AWS/Lambda"
|
||||||
|
period = "120"
|
||||||
|
statistic = "Sum"
|
||||||
|
threshold = "0"
|
||||||
|
alarm_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
ok_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
treat_missing_data = "notBreaching"
|
||||||
|
dimensions = {
|
||||||
|
FunctionName = var.jitprovisioner.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_metric_alarm" "deprovisioner" {
|
||||||
|
for_each = toset(["ExecutionsFailed"])
|
||||||
|
alarm_name = "${var.prefix}-deprovisioner-${each.key}"
|
||||||
|
comparison_operator = "GreaterThanThreshold"
|
||||||
|
evaluation_periods = "1"
|
||||||
|
metric_name = each.key
|
||||||
|
namespace = "AWS/States"
|
||||||
|
period = "120"
|
||||||
|
statistic = "Sum"
|
||||||
|
threshold = "0"
|
||||||
|
alarm_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
ok_actions = [module.notify_slack.slack_topic_arn]
|
||||||
|
treat_missing_data = "notBreaching"
|
||||||
|
dimensions = {
|
||||||
|
StateMachineArn = var.deprovisioner.arn
|
||||||
|
}
|
||||||
|
}
|
7
infrastructure/sandbox/Monitoring/variables.tf
Normal file
7
infrastructure/sandbox/Monitoring/variables.tf
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
variable "prefix" {}
|
||||||
|
variable "lb" {}
|
||||||
|
variable "jitprovisioner" {}
|
||||||
|
variable "deprovisioner" {}
|
||||||
|
variable "slack_webhook" {}
|
||||||
|
variable "dynamodb_table" {}
|
||||||
|
variable "kms_key" {}
|
1
infrastructure/sandbox/PreProvisioner/.gitignore
vendored
Normal file
1
infrastructure/sandbox/PreProvisioner/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.lambda.zip
|
2
infrastructure/sandbox/PreProvisioner/lambda/.gitignore
vendored
Normal file
2
infrastructure/sandbox/PreProvisioner/lambda/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
lambda
|
||||||
|
deploy_terraform/backend.conf
|
18
infrastructure/sandbox/PreProvisioner/lambda/Dockerfile
Normal file
18
infrastructure/sandbox/PreProvisioner/lambda/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
FROM golang:1.18-alpine AS builder
|
||||||
|
RUN apk update && apk add --no-cache git curl openssl unzip
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . .
|
||||||
|
RUN go get -d -v
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-extldflags '-static'"
|
||||||
|
RUN curl https://releases.hashicorp.com/terraform/1.1.8/terraform_1.1.8_linux_amd64.zip > terraform.zip
|
||||||
|
RUN unzip terraform.zip
|
||||||
|
RUN rm terraform.zip
|
||||||
|
RUN chmod 644 $(find . -type f)
|
||||||
|
RUN chmod 755 $(find . -type d)
|
||||||
|
RUN chmod 655 lambda terraform
|
||||||
|
|
||||||
|
#FROM scratch
|
||||||
|
#COPY --from=builder /build/lambda /build/terraform /
|
||||||
|
#COPY --from=builder /build/deploy_terraform /deploy_terraform
|
||||||
|
#COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
|
ENTRYPOINT ["/build/lambda"]
|
@ -0,0 +1,6 @@
|
|||||||
|
bucket = "${remote_state.state_bucket.id}"
|
||||||
|
key = "terraform.tfstate" # This should be set to account_alias/unique_key/terraform.tfstate
|
||||||
|
region = "us-east-2"
|
||||||
|
encrypt = true
|
||||||
|
kms_key_id = "${remote_state.kms_key.id}"
|
||||||
|
dynamodb_table = "${remote_state.dynamodb_table.id}"
|
@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
description: A Helm chart for Fleet
|
||||||
|
name: fleet
|
||||||
|
keywords:
|
||||||
|
- fleet
|
||||||
|
- osquery
|
||||||
|
version: v4.12.0
|
||||||
|
home: https://github.com/fleetdm/fleet
|
||||||
|
sources:
|
||||||
|
- https://github.com/fleetdm/fleet.git
|
||||||
|
appVersion: v4.12.0
|
@ -0,0 +1,56 @@
|
|||||||
|
## Fleet Helm Chart
|
||||||
|
|
||||||
|
This directory contains a Helm Chart that makes deploying Fleet on Kubernetes easy.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
#### 1. Create namespace
|
||||||
|
|
||||||
|
This Helm chart optionally provisions a Kubernetes namespace. Alternatively, you can add one with `kubectl create namespace <name>` or by creating a YAML file containing the namespace and applying it to your cluster.
|
||||||
|
|
||||||
|
#### 2. Create the necessary secrets
|
||||||
|
|
||||||
|
This Helm chart optionally creates Kubernetes `Secret`s for MySQL and Redis necessary for Fleet to operate. If you manually create them instead, at a minimum, secrets for the MySQL password must be created. For example, if you are deploying into a namespace called `fleet`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
kind: Secret
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: mysql
|
||||||
|
namespace: fleet
|
||||||
|
stringData:
|
||||||
|
mysql-password: this-is-a-bad-password
|
||||||
|
```
|
||||||
|
|
||||||
|
If you use Fleet's TLS capabilities, TLS connections to the MySQL server, or AWS access secret keys, additional secrets and keys are needed. The name of each `Secret` must match the value of `secretName` for each section in the `values.yaml` file and the key of each secret must match the related key value from the values file. For example, to configure Fleet's TLS, you would use a Secret like the one below.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
kind: Secret
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: fleet
|
||||||
|
namespace: fleet
|
||||||
|
stringData:
|
||||||
|
server.cert: |
|
||||||
|
your-pem-encoded-certificate-here
|
||||||
|
server.key: |
|
||||||
|
your-pem-encoded-key-here
|
||||||
|
```
|
||||||
|
|
||||||
|
Once all of your secrets are configured, use `kubectl apply -f <secret_file_name.yaml> --namespace <your_namespace>` to create them in the cluster.
|
||||||
|
|
||||||
|
#### 3. Further Configuration
|
||||||
|
|
||||||
|
To configure how Fleet runs, such as specifying the number of Fleet instances to deploy or changing the logger plugin for Fleet, edit the `values.yaml` file to your desired settings.
|
||||||
|
|
||||||
|
#### 4. Deploy Fleet
|
||||||
|
|
||||||
|
Once the secrets have been created and you have updated the values to match your required configuration, you can deploy with the following command.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
helm upgrade --install fleet fleet \
|
||||||
|
--namespace <your_namespace> \
|
||||||
|
--repo https://fleetdm.github.io/fleet/charts \
|
||||||
|
--values values.yaml
|
||||||
|
```
|
@ -0,0 +1,353 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicas }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | trim | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- with .Values.podLabels }}
|
||||||
|
{{- toYaml . | trim | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ .Values.fleetName }}
|
||||||
|
command: [/usr/bin/fleet]
|
||||||
|
args: ["serve"]
|
||||||
|
image: fleetdm/fleet:{{ .Values.imageTag }}
|
||||||
|
ports:
|
||||||
|
- name: {{ .Values.fleetName }}
|
||||||
|
containerPort: {{ .Values.fleet.listenPort }}
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: {{ .Values.resources.limits.cpu }}
|
||||||
|
memory: {{ .Values.resources.limits.memory }}
|
||||||
|
requests:
|
||||||
|
cpu: {{ .Values.resources.requests.cpu }}
|
||||||
|
memory: {{ .Values.resources.requests.memory }}
|
||||||
|
env:
|
||||||
|
## BEGIN FLEET SECTION
|
||||||
|
- name: FLEET_DEMO
|
||||||
|
value: "1"
|
||||||
|
- name: FLEET_SERVER_ADDRESS
|
||||||
|
value: "0.0.0.0:{{ .Values.fleet.listenPort }}"
|
||||||
|
- name: FLEET_AUTH_BCRYPT_COST
|
||||||
|
value: "{{ .Values.fleet.auth.bcryptCost }}"
|
||||||
|
- name: FLEET_AUTH_SALT_KEY_SIZE
|
||||||
|
value: "{{ .Values.fleet.auth.saltKeySize }}"
|
||||||
|
- name: FLEET_APP_TOKEN_KEY_SIZE
|
||||||
|
value: "{{ .Values.fleet.app.tokenKeySize }}"
|
||||||
|
- name: FLEET_APP_TOKEN_VALIDITY_PERIOD
|
||||||
|
value: "{{ .Values.fleet.app.inviteTokenValidityPeriod }}"
|
||||||
|
- name: FLEET_SESSION_KEY_SIZE
|
||||||
|
value: "{{ .Values.fleet.session.keySize }}"
|
||||||
|
- name: FLEET_SESSION_DURATION
|
||||||
|
value: "{{ .Values.fleet.session.duration }}"
|
||||||
|
- name: FLEET_LOGGING_DEBUG
|
||||||
|
value: "{{ .Values.fleet.logging.debug }}"
|
||||||
|
- name: FLEET_LOGGING_JSON
|
||||||
|
value: "{{ .Values.fleet.logging.json }}"
|
||||||
|
- name: FLEET_LOGGING_DISABLE_BANNER
|
||||||
|
value: "{{ .Values.fleet.logging.disableBanner }}"
|
||||||
|
- name: FLEET_SERVER_TLS
|
||||||
|
value: "{{ .Values.fleet.tls.enabled }}"
|
||||||
|
{{- if .Values.fleet.tls.enabled }}
|
||||||
|
- name: FLEET_SERVER_TLS_COMPATIBILITY
|
||||||
|
value: "{{ .Values.fleet.tls.compatibility }}"
|
||||||
|
- name: FLEET_SERVER_CERT
|
||||||
|
value: "/secrets/tls/{{ .Values.fleet.tls.certSecretKey }}"
|
||||||
|
- name: FLEET_SERVER_KEY
|
||||||
|
value: "/secrets/tls/{{ .Values.fleet.tls.keySecretKey }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if ne .Values.fleet.carving.s3.bucketName "" }}
|
||||||
|
- name: FLEET_S3_BUCKET
|
||||||
|
value: "{{ .Values.fleet.carving.s3.bucketName }}"
|
||||||
|
- name: FLEET_S3_PREFIX
|
||||||
|
value: "{{ .Values.fleet.carving.s3.prefix }}"
|
||||||
|
{{- if ne .Values.fleet.carving.s3.accessKeyID "" }}
|
||||||
|
- name: FLEET_S3_ACCESS_KEY_ID
|
||||||
|
value: "{{ .Values.fleet.carving.s3.accessKeyID }}"
|
||||||
|
- name: FLEET_S3_SECRET_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.fleet.secretName }}"
|
||||||
|
key: "{{ .Values.fleet.carving.s3.secretKey }}"
|
||||||
|
{{ else }}
|
||||||
|
- name: FLEET_S3_STS_ASSUME_ROLE_ARN
|
||||||
|
value: "{{ .Values.fleet.carving.s3.stsAssumeRoleARN }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
## END FLEET SECTION
|
||||||
|
## BEGIN MYSQL SECTION
|
||||||
|
- name: FLEET_MYSQL_ADDRESS
|
||||||
|
value: "{{ .Values.mysql.address }}"
|
||||||
|
- name: FLEET_MYSQL_DATABASE
|
||||||
|
value: "{{ .Values.mysql.database }}"
|
||||||
|
- name: FLEET_MYSQL_USERNAME
|
||||||
|
value: "{{ .Values.mysql.username }}"
|
||||||
|
- name: FLEET_MYSQL_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.mysql.secretName }}
|
||||||
|
key: {{ .Values.mysql.passwordKey }}
|
||||||
|
- name: FLEET_MYSQL_MAX_OPEN_CONNS
|
||||||
|
value: "{{ .Values.mysql.maxOpenConns }}"
|
||||||
|
- name: FLEET_MYSQL_MAX_IDLE_CONNS
|
||||||
|
value: "{{ .Values.mysql.maxIdleConns }}"
|
||||||
|
- name: FLEET_MYSQL_CONN_MAX_LIFETIME
|
||||||
|
value: "{{ .Values.mysql.connMaxLifetime }}"
|
||||||
|
{{- if .Values.mysql.tls.enabled }}
|
||||||
|
- name: FLEET_MYSQL_TLS_CA
|
||||||
|
value: "/secrets/mysql/{{ .Values.mysql.tls.caCertKey }}"
|
||||||
|
- name: FLEET_MYSQL_TLS_CERT
|
||||||
|
value: "/secrets/mysql/{{ .Values.mysql.tls.certKey }}"
|
||||||
|
- name: FLEET_MYSQL_TLS_KEY
|
||||||
|
value: "/secrets/mysql/{{ .Values.mysql.tls.keyKey }}"
|
||||||
|
- name: FLEET_MYSQL_TLS_CONFIG
|
||||||
|
value: "{{ .Values.mysql.tls.config }}"
|
||||||
|
- name: FLEET_MYSQL_TLS_SERVER_NAME
|
||||||
|
value: "{{ .Values.mysql.tls.serverName }}"
|
||||||
|
{{- end }}
|
||||||
|
## END MYSQL SECTION
|
||||||
|
## BEGIN REDIS SECTION
|
||||||
|
- name: FLEET_REDIS_ADDRESS
|
||||||
|
value: "{{ .Values.redis.address }}"
|
||||||
|
- name: FLEET_REDIS_DATABASE
|
||||||
|
value: "{{ .Values.redis.database }}"
|
||||||
|
{{- if .Values.redis.usePassword }}
|
||||||
|
- name: FLEET_REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.redis.secretName }}"
|
||||||
|
key: "{{ .Values.redis.passwordKey }}"
|
||||||
|
{{- end }}
|
||||||
|
## END REDIS SECTION
|
||||||
|
## BEGIN OSQUERY SECTION
|
||||||
|
- name: FLEET_OSQUERY_NODE_KEY_SIZE
|
||||||
|
value: "{{ .Values.osquery.nodeKeySize }}"
|
||||||
|
- name: FLEET_OSQUERY_LABEL_UPDATE_INTERVAL
|
||||||
|
value: "{{ .Values.osquery.labelUpdateInterval }}"
|
||||||
|
- name: FLEET_OSQUERY_DETAIL_UPDATE_INTERVAL
|
||||||
|
value: "{{ .Values.osquery.detailUpdateInterval }}"
|
||||||
|
- name: FLEET_OSQUERY_STATUS_LOG_PLUGIN
|
||||||
|
value: "{{ .Values.osquery.logging.statusPlugin }}"
|
||||||
|
- name: FLEET_OSQUERY_RESULT_LOG_PLUGIN
|
||||||
|
value: "{{ .Values.osquery.logging.resultPlugin }}"
|
||||||
|
{{- if eq .Values.osquery.logging.statusPlugin "filesystem" }}
|
||||||
|
- name: FLEET_FILESYSTEM_STATUS_LOG_FILE
|
||||||
|
value: "/logs/{{ .Values.osquery.logging.filesystem.statusLogFile }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq .Values.osquery.logging.resultPlugin "filesystem" }}
|
||||||
|
- name: FLEET_FILESYSTEM_RESULT_LOG_FILE
|
||||||
|
value: "/logs/{{ .Values.osquery.logging.filesystem.resultLogFile }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if or (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
|
||||||
|
- name: FLEET_FILESYSTEM_ENABLE_LOG_ROTATION
|
||||||
|
value: "{{ .Values.osquery.logging.filesystem.enableRotation }}"
|
||||||
|
- name: FLEET_FILESYSTEM_ENABLE_LOG_COMPRESSION
|
||||||
|
value: "{{ .Values.osquery.logging.filesystem.enableCompression }}"
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if or (eq .Values.osquery.logging.statusPlugin "firehose") (eq .Values.osquery.logging.resultPlugin "firehose") }}
|
||||||
|
- name: FLEET_FIREHOSE_REGION
|
||||||
|
value: "{{ .Values.osquery.logging.firehose.region }}"
|
||||||
|
{{- if eq .Values.osquery.logging.statusPlugin "firehose" }}
|
||||||
|
- name: FLEET_FIREHOSE_STATUS_STREAM
|
||||||
|
value: "{{ .Values.osquery.logging.firehose.statusStream }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq .Values.osquery.logging.resultPlugin "firehose" }}
|
||||||
|
- name: FLEET_FIREHOSE_RESULT_STREAM
|
||||||
|
value: "{{ .Values.osquery.logging.firehose.resultStream }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if ne .Values.osquery.logging.firehose.accessKeyID "" }}
|
||||||
|
- name: FLEET_FIREHOSE_ACCESS_KEY_ID
|
||||||
|
value: "{{ .Values.osquery.logging.firehose.accessKeyID }}"
|
||||||
|
- name: FLEET_FIREHOSE_SECRET_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.osquery.secretName }}"
|
||||||
|
key: "{{ .Values.osquery.logging.firehose.secretKey }}"
|
||||||
|
{{ else }}
|
||||||
|
- name: FLEET_FIREHOSE_STS_ASSUME_ROLE_ARN
|
||||||
|
value: "{{ .Values.osquery.logging.firehose.stsAssumeRoleARN }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if or (eq .Values.osquery.logging.statusPlugin "kinesis") (eq .Values.osquery.logging.resultPlugin "kinesis") }}
|
||||||
|
- name: FLEET_KINESIS_REGION
|
||||||
|
value: "{{ .Values.osquery.logging.kinesis.region }}"
|
||||||
|
{{- if eq .Values.osquery.logging.statusPlugin "kinesis" }}
|
||||||
|
- name: FLEET_KINESIS_STATUS_STREAM
|
||||||
|
value: "{{ .Values.osquery.logging.kinesis.statusStream }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq .Values.osquery.logging.resultPlugin "kinesis" }}
|
||||||
|
- name: FLEET_KINESIS_RESULT_STREAM
|
||||||
|
value: "{{ .Values.osquery.logging.kinesis.resultStream }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if ne .Values.osquery.logging.kinesis.accessKeyID "" }}
|
||||||
|
- name: FLEET_KINESIS_ACCESS_KEY_ID
|
||||||
|
value: "{{ .Values.osquery.logging.kinesis.accessKeyID }}"
|
||||||
|
- name: FLEET_KINESIS_SECRET_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.osquery.secretName }}"
|
||||||
|
key: "{{ .Values.osquery.logging.kinesis.secretKey }}"
|
||||||
|
{{ else }}
|
||||||
|
- name: FLEET_KINESIS_STS_ASSUME_ROLE_ARN
|
||||||
|
value: "{{ .Values.osquery.logging.kinesis.stsAssumeRoleARN }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if or (eq .Values.osquery.logging.statusPlugin "lambda") (eq .Values.osquery.logging.resultPlugin "lambda") }}
|
||||||
|
- name: FLEET_LAMBDA_REGION
|
||||||
|
value: "{{ .Values.osquery.logging.lambda.region }}"
|
||||||
|
{{- if eq .Values.osquery.logging.statusPlugin "lambda" }}
|
||||||
|
- name: FLEET_LAMBDA_STATUS_FUNCTION
|
||||||
|
value: "{{ .Values.osquery.logging.lambda.statusFunction }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq .Values.osquery.logging.resultPlugin "lambda" }}
|
||||||
|
- name: FLEET_LAMBDA_RESULT_FUNCTION
|
||||||
|
value: "{{ .Values.osquery.logging.lambda.resultFunction }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if ne .Values.osquery.logging.lambda.accessKeyID "" }}
|
||||||
|
- name: FLEET_LAMBDA_ACCESS_KEY_ID
|
||||||
|
value: "{{ .Values.osquery.logging.lambda.accessKeyID }}"
|
||||||
|
- name: FLEET_LAMBDA_SECRET_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.osquery.secretName }}"
|
||||||
|
key: "{{ .Values.osquery.logging.lambda.secretKey }}"
|
||||||
|
{{ else }}
|
||||||
|
- name: FLEET_LAMBDA_STS_ASSUME_ROLE_ARN
|
||||||
|
value: "{{ .Values.osquery.logging.lambda.stsAssumeRoleARN }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
|
||||||
|
{{- if or (eq .Values.osquery.logging.statusPlugin "pubsub") (eq .Values.osquery.logging.resultPlugin "pubsub") }}
|
||||||
|
- name: FLEET_PUBSUB_PROJECT
|
||||||
|
value: "{{ .Values.osquery.logging.pubsub.project }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq .Values.osquery.logging.statusPlugin "pubsub" }}
|
||||||
|
- name: FLEET_PUBSUB_STATUS_TOPIC
|
||||||
|
value: "{{ .Values.osquery.logging.pubsub.statusTopic }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq .Values.osquery.logging.resultPlugin "pubsub" }}
|
||||||
|
- name: FLEET_PUBSUB_RESULT_TOPIC
|
||||||
|
value: "{{ .Values.osquery.logging.pubsub.resultTopic }}"
|
||||||
|
{{- end }}
|
||||||
|
## END OSQUERY SECTION
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop: [ALL]
|
||||||
|
privileged: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsGroup: 3333
|
||||||
|
runAsUser: 3333
|
||||||
|
runAsNonRoot: true
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: {{ .Values.fleet.listenPort }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: {{ .Values.fleet.listenPort }}
|
||||||
|
{{- if or (.Values.fleet.tls.enabled) (.Values.mysql.tls.enabled) (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
|
||||||
|
volumeMounts:
|
||||||
|
{{- if .Values.fleet.tls.enabled }}
|
||||||
|
- name: {{ .Values.fleetName }}-tls
|
||||||
|
readOnly: true
|
||||||
|
mountPath: /secrets/tls
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.mysql.tls.enabled }}
|
||||||
|
- name: mysql-tls
|
||||||
|
readOnly: true
|
||||||
|
mountPath: /secrets/mysql
|
||||||
|
{{- end }}
|
||||||
|
{{- if or (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
|
||||||
|
- name: osquery-logs
|
||||||
|
mountPath: /logs
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.gke.cloudSQL.enableProxy }}
|
||||||
|
- name: cloudsql-proxy
|
||||||
|
image: "gcr.io/cloudsql-docker/gce-proxy:{{ .Values.gke.cloudSQL.imageTag }}"
|
||||||
|
command:
|
||||||
|
- "/cloud_sql_proxy"
|
||||||
|
- "-verbose={{ .Values.gke.cloudSQL.verbose}}"
|
||||||
|
- "-instances={{ .Values.gke.cloudSQL.instanceName }}=tcp:3306"
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 0.5 # 500Mhz
|
||||||
|
memory: 150Mi
|
||||||
|
requests:
|
||||||
|
cpu: 0.1 # 100Mhz
|
||||||
|
memory: 50Mi
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop: [ALL]
|
||||||
|
privileged: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsGroup: 3333
|
||||||
|
runAsUser: 3333
|
||||||
|
runAsNonRoot: true
|
||||||
|
{{- end }}
|
||||||
|
hostPID: false
|
||||||
|
hostNetwork: false
|
||||||
|
hostIPC: false
|
||||||
|
serviceAccountName: {{ .Values.fleetName }}
|
||||||
|
{{- if or (.Values.fleet.tls.enabled) (.Values.mysql.tls.enabled) (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
|
||||||
|
volumes:
|
||||||
|
{{- if .Values.fleet.tls.enabled }}
|
||||||
|
- name: {{ .Values.fleetName }}-tls
|
||||||
|
secret:
|
||||||
|
secretName: "{{ .Values.fleet.secretName }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.mysql.tls.enabled }}
|
||||||
|
- name: mysql-tls
|
||||||
|
secret:
|
||||||
|
secretName: "{{ .Values.mysql.secretName }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- if or (eq .Values.osquery.logging.statusPlugin "filesystem") (eq .Values.osquery.logging.resultPlugin "filesystem") }}
|
||||||
|
- name: osquery-logs
|
||||||
|
emptyDir:
|
||||||
|
sizeLimit: "{{ .Values.osquery.logging.filesystem.volumeSize }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
@ -0,0 +1,9 @@
|
|||||||
|
{{- if .Values.gke.ingress.useManagedCertificate }}
|
||||||
|
apiVersion: networking.gke.io/v1
|
||||||
|
kind: ManagedCertificate
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
spec:
|
||||||
|
domains:
|
||||||
|
- {{ .Values.hostName }}
|
||||||
|
{{- end }}
|
@ -0,0 +1,39 @@
|
|||||||
|
{{- if .Values.createIngress }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
{{- if or .Values.ingressAnnotations .Values.gke.useGKEIngress }}
|
||||||
|
annotations:
|
||||||
|
{{- range $key, $value := $.Values.ingressAnnotations }}
|
||||||
|
{{ $key }}: {{ $value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.gke.ingress.useGKEIngress }}
|
||||||
|
kubernetes.io/ingress.class: gce
|
||||||
|
{{- if .Values.gke.ingress.useManagedCertificate }}
|
||||||
|
kubernetes.io/ingress.allow-http: "false"
|
||||||
|
networking.gke.io/managed-certificates: fleet
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
app: {{ .Values.fleetName }}
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.hostName }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
# Next line required in k8s 1.19 and not supported in <=1.17
|
||||||
|
# pathType: Exact
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
|
pathType: Prefix
|
||||||
|
{{- end }}
|
@ -0,0 +1,134 @@
|
|||||||
|
{{- if .Values.fleet.autoApplySQLMigrations }}
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Values.fleetName }}-migration
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | trim | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: {{ .Values.fleetName }}-migration
|
||||||
|
command: [/usr/bin/fleet]
|
||||||
|
args: ["prepare","db","--no-prompt"]
|
||||||
|
image: fleetdm/fleet:{{ .Values.imageTag }}
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: {{ .Values.resources.limits.cpu }}
|
||||||
|
memory: {{ .Values.resources.limits.memory }}
|
||||||
|
requests:
|
||||||
|
cpu: {{ .Values.resources.requests.cpu }}
|
||||||
|
memory: {{ .Values.resources.requests.memory }}
|
||||||
|
env:
|
||||||
|
- name: FLEET_SERVER_ADDRESS
|
||||||
|
value: "0.0.0.0:{{ .Values.fleet.listenPort }}"
|
||||||
|
- name: FLEET_AUTH_BCRYPT_COST
|
||||||
|
value: "{{ .Values.fleet.auth.bcryptCost }}"
|
||||||
|
- name: FLEET_AUTH_SALT_KEY_SIZE
|
||||||
|
value: "{{ .Values.fleet.auth.saltKeySize }}"
|
||||||
|
- name: FLEET_APP_TOKEN_KEY_SIZE
|
||||||
|
value: "{{ .Values.fleet.app.tokenKeySize }}"
|
||||||
|
- name: FLEET_APP_TOKEN_VALIDITY_PERIOD
|
||||||
|
value: "{{ .Values.fleet.app.inviteTokenValidityPeriod }}"
|
||||||
|
- name: FLEET_SESSION_KEY_SIZE
|
||||||
|
value: "{{ .Values.fleet.session.keySize }}"
|
||||||
|
- name: FLEET_SESSION_DURATION
|
||||||
|
value: "{{ .Values.fleet.session.duration }}"
|
||||||
|
- name: FLEET_LOGGING_DEBUG
|
||||||
|
value: "{{ .Values.fleet.logging.debug }}"
|
||||||
|
- name: FLEET_LOGGING_JSON
|
||||||
|
value: "{{ .Values.fleet.logging.json }}"
|
||||||
|
- name: FLEET_LOGGING_DISABLE_BANNER
|
||||||
|
value: "{{ .Values.fleet.logging.disableBanner }}"
|
||||||
|
- name: FLEET_SERVER_TLS
|
||||||
|
value: "{{ .Values.fleet.tls.enabled }}"
|
||||||
|
{{- if .Values.fleet.tls.enabled }}
|
||||||
|
- name: FLEET_SERVER_TLS_COMPATIBILITY
|
||||||
|
value: "{{ .Values.fleet.tls.compatibility }}"
|
||||||
|
- name: FLEET_SERVER_CERT
|
||||||
|
value: "/secrets/tls/{{ .Values.fleet.tls.certSecretKey }}"
|
||||||
|
- name: FLEET_SERVER_KEY
|
||||||
|
value: "/secrets/tls/{{ .Values.fleet.tls.keySecretKey }}"
|
||||||
|
{{- end }}
|
||||||
|
## END FLEET SECTION
|
||||||
|
## BEGIN MYSQL SECTION
|
||||||
|
- name: FLEET_MYSQL_ADDRESS
|
||||||
|
value: "{{ .Values.mysql.address }}"
|
||||||
|
- name: FLEET_MYSQL_DATABASE
|
||||||
|
value: "{{ .Values.mysql.database }}"
|
||||||
|
- name: FLEET_MYSQL_USERNAME
|
||||||
|
value: "{{ .Values.mysql.username }}"
|
||||||
|
- name: FLEET_MYSQL_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.mysql.secretName }}
|
||||||
|
key: {{ .Values.mysql.passwordKey }}
|
||||||
|
- name: FLEET_MYSQL_MAX_OPEN_CONNS
|
||||||
|
value: "{{ .Values.mysql.maxOpenConns }}"
|
||||||
|
- name: FLEET_MYSQL_MAX_IDLE_CONNS
|
||||||
|
value: "{{ .Values.mysql.maxIdleConns }}"
|
||||||
|
- name: FLEET_MYSQL_CONN_MAX_LIFETIME
|
||||||
|
value: "{{ .Values.mysql.connMaxLifetime }}"
|
||||||
|
{{- if .Values.mysql.tls.enabled }}
|
||||||
|
- name: FLEET_MYSQL_TLS_CA
|
||||||
|
value: "/secrets/mysql/{{ .Values.mysql.tls.caCertKey }}"
|
||||||
|
- name: FLEET_MYSQL_TLS_CERT
|
||||||
|
value: "/secrets/mysql/{{ .Values.mysql.tls.certKey }}"
|
||||||
|
- name: FLEET_MYSQL_TLS_KEY
|
||||||
|
value: "/secrets/mysql/{{ .Values.mysql.tls.keyKey }}"
|
||||||
|
- name: FLEET_MYSQL_TLS_CONFIG
|
||||||
|
value: "{{ .Values.mysql.tls.config }}"
|
||||||
|
- name: FLEET_MYSQL_TLS_SERVER_NAME
|
||||||
|
value: "{{ .Values.mysql.tls.serverName }}"
|
||||||
|
{{- end }}
|
||||||
|
## END MYSQL SECTION
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop: [ALL]
|
||||||
|
privileged: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsGroup: 3333
|
||||||
|
runAsUser: 3333
|
||||||
|
runAsNonRoot: true
|
||||||
|
volumeMounts:
|
||||||
|
{{- if .Values.mysql.tls.enabled }}
|
||||||
|
- name: mysql-tls
|
||||||
|
readOnly: true
|
||||||
|
mountPath: /secrets/mysql
|
||||||
|
{{- end }}
|
||||||
|
volumes:
|
||||||
|
{{- if .Values.mysql.tls.enabled }}
|
||||||
|
- name: mysql-tls
|
||||||
|
secret:
|
||||||
|
secretName: "{{ .Values.mysql.secretName }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
@ -0,0 +1,11 @@
|
|||||||
|
{{- if .Values.createNamespace }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Release.Namespace }}
|
||||||
|
{{- end }}
|
@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- core
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
resourceNames:
|
||||||
|
- {{ .Values.mysql.secretName }}
|
||||||
|
- {{ .Values.redis.secretName }}
|
||||||
|
- {{ .Values.fleet.secretName }}
|
||||||
|
- {{ .Values.osquery.secretName }}
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
subjects:
|
||||||
|
- apiGroup: ""
|
||||||
|
kind: ServiceAccount
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
{{- if or .Values.serviceAccountAnnotations .Values.gke.workloadIdentityEmail }}
|
||||||
|
annotations:
|
||||||
|
{{- with .Values.serviceAccountAnnotations}}
|
||||||
|
{{ toYaml . | trim | indent 2}}
|
||||||
|
{{- end }}
|
||||||
|
{{- if ne .Values.gke.workloadIdentityEmail "" }}
|
||||||
|
iam.gke.io/gcp-service-account: {{ .Values.gke.workloadIdentityEmail }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
@ -0,0 +1,31 @@
|
|||||||
|
{{- if .Values.mysql.createSecret }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Values.mysql.secretName }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
stringData:
|
||||||
|
{{ .Values.mysql.passwordKey }}: {{ .Values.mysql.password | quote }}
|
||||||
|
type: Opaque
|
||||||
|
---
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.redis.createSecret }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Values.redis.secretName }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
stringData:
|
||||||
|
{{ .Values.redis.passwordKey }}: {{ .Values.redis.password }}
|
||||||
|
type: Opaque
|
||||||
|
{{- end }}
|
@ -0,0 +1,22 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
name: {{ .Values.fleetName }}
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: fleet
|
||||||
|
chart: fleet
|
||||||
|
heritage: {{ .Release.Service }}
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
ports:
|
||||||
|
- name: {{ .Values.fleetName }}
|
||||||
|
port: {{ .Values.fleet.listenPort }}
|
||||||
|
{{- if .Values.gke.ingress.useGKEIngress }}
|
||||||
|
type: NodePort
|
||||||
|
{{- end }}
|
@ -0,0 +1,183 @@
|
|||||||
|
## Section: Kubernetes
|
||||||
|
# All settings related to how Fleet is deployed in Kubernetes
|
||||||
|
# The name used for deployment/role/sa/etc. Useful for when deploying multiple separate
|
||||||
|
# fleet instances into the same Namespace.
|
||||||
|
fleetName: fleet
|
||||||
|
hostName: fleet.localhost
|
||||||
|
replicas: 3 # The number of Fleet instances to deploy
|
||||||
|
imageTag: v4.12.0 # Version of Fleet to deploy
|
||||||
|
createNamespace: false # Whether or not to automatically create the Namespace
|
||||||
|
createIngress: true # Whether or not to automatically create an Ingress
|
||||||
|
ingressAnnotations: {} # Additional annotation to add to the Ingress
|
||||||
|
podLabels: {} # Additional labels to add to the Fleet pod
|
||||||
|
podAnnotations: {} # Additional annotations to add to the Fleet pod
|
||||||
|
serviceAccountAnnotations: {} # Additional annotations to add to the Fleet service account
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 1 # 1GHz
|
||||||
|
memory: 1Gi
|
||||||
|
requests:
|
||||||
|
cpu: 0.1 # 100Mhz
|
||||||
|
memory: 50Mi
|
||||||
|
|
||||||
|
# Node labels for pod assignment
|
||||||
|
# ref: https://kubernetes.io/docs/user-guide/node-selection/
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
# Tolerations for pod assignment
|
||||||
|
# ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
# Configurable affinity for pod assignment
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- podAffinityTerm:
|
||||||
|
labelSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: app
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- fleet
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
weight: 100
|
||||||
|
|
||||||
|
## Section: Fleet
|
||||||
|
# All of the settings relating to configuring the Fleet server
|
||||||
|
fleet:
|
||||||
|
listenPort: 8080
|
||||||
|
# Name of the Secret resource storing TLS and S3 bucket secrets
|
||||||
|
secretName: fleet
|
||||||
|
# Whether or not to run `fleet db prepare` to run SQL migrations before starting Fleet
|
||||||
|
autoApplySQLMigrations: true
|
||||||
|
tls:
|
||||||
|
enabled: true
|
||||||
|
compatibility: modern
|
||||||
|
certSecretKey: server.cert
|
||||||
|
keySecretKey: server.key
|
||||||
|
auth:
|
||||||
|
bcryptCost: 12
|
||||||
|
saltKeySize: 24
|
||||||
|
app:
|
||||||
|
tokenKeySize: 24
|
||||||
|
inviteTokenValidityPeriod: 120h # 5 days
|
||||||
|
session:
|
||||||
|
keySize: 64
|
||||||
|
duration: 2160h # 90 days
|
||||||
|
logging:
|
||||||
|
debug: false
|
||||||
|
json: false
|
||||||
|
disableBanner: false
|
||||||
|
carving:
|
||||||
|
s3:
|
||||||
|
bucketName: ""
|
||||||
|
prefix: ""
|
||||||
|
accessKeyID: ""
|
||||||
|
secretKey: s3-bucket
|
||||||
|
stsAssumeRoleARN: ""
|
||||||
|
|
||||||
|
## Section: osquery
|
||||||
|
# All of the settings related to osquery's interactions with the Fleet server
|
||||||
|
osquery:
|
||||||
|
# Name of the secret resource containing optional secrets for AWS credentials
|
||||||
|
secretName: osquery
|
||||||
|
nodeKeySize: 24
|
||||||
|
labelUpdateInterval: 30m
|
||||||
|
detailUpdateInterval: 30m
|
||||||
|
|
||||||
|
# To change where Fleet store the logs sent from osquery, set the values below
|
||||||
|
logging:
|
||||||
|
statusPlugin: filesystem
|
||||||
|
resultPlugin: filesystem
|
||||||
|
|
||||||
|
# To congigure the filesystem logger, change the values below
|
||||||
|
filesystem:
|
||||||
|
statusLogFile: osquery_status # will be placed in the /logs volume
|
||||||
|
resultLogFile: osquery_result # will be placed in the /logs volume
|
||||||
|
enableRotation: false
|
||||||
|
enableCompression: false
|
||||||
|
volumeSize: 20Gi # the maximum size of the volume
|
||||||
|
|
||||||
|
# To configure the AWS Firehose logger, change the values below
|
||||||
|
firehose:
|
||||||
|
region: ""
|
||||||
|
accessKeyID: ""
|
||||||
|
secretKey: firehose
|
||||||
|
stsAssumeRoleARN: ""
|
||||||
|
statusStream: ""
|
||||||
|
resultStream: ""
|
||||||
|
|
||||||
|
# To configure the AWS Kinesis logger, change the values below
|
||||||
|
kinesis:
|
||||||
|
region: ""
|
||||||
|
accessKeyID: ""
|
||||||
|
secretKey: kinesis
|
||||||
|
stsAssumeRoleARN: ""
|
||||||
|
statusStream: ""
|
||||||
|
resultStream: ""
|
||||||
|
|
||||||
|
# To configure the AWS Lambda logger, change the values below
|
||||||
|
lambda:
|
||||||
|
region: ""
|
||||||
|
accessKeyID: ""
|
||||||
|
secretKey: lambda
|
||||||
|
stsAssumeRoleARN: ""
|
||||||
|
statusFunction: ""
|
||||||
|
resultFunction: ""
|
||||||
|
|
||||||
|
# To configure the GCP PubSub logger, change the values below
|
||||||
|
pubsub:
|
||||||
|
project: ""
|
||||||
|
statusTopic: ""
|
||||||
|
resultTopic: ""
|
||||||
|
|
||||||
|
## Section: MySQL
|
||||||
|
# All of the connection settings for MySQL
|
||||||
|
mysql:
|
||||||
|
createSecret: false
|
||||||
|
# Name of the Secret resource containing MySQL password and TLS secrets
|
||||||
|
secretName: mysql
|
||||||
|
address: 127.0.0.1:3306
|
||||||
|
database: fleet
|
||||||
|
username: fleet
|
||||||
|
# Only needed if creating secret.
|
||||||
|
password: default
|
||||||
|
passwordKey: mysql-password
|
||||||
|
maxOpenConns: 50
|
||||||
|
maxIdleConns: 50
|
||||||
|
connMaxLifetime: 0
|
||||||
|
tls:
|
||||||
|
enabled: false
|
||||||
|
caCertKey: ca.cert
|
||||||
|
certKey: client.cert
|
||||||
|
keyKey: client.key
|
||||||
|
config: ""
|
||||||
|
serverName: ""
|
||||||
|
|
||||||
|
## Section: Redis
|
||||||
|
# All of the connection settings for Redis
|
||||||
|
redis:
|
||||||
|
createSecret: false
|
||||||
|
address: 127.0.0.1:6379
|
||||||
|
database: "0"
|
||||||
|
usePassword: false
|
||||||
|
secretName: redis
|
||||||
|
# Only needed if creating secret.
|
||||||
|
password: default
|
||||||
|
passwordKey: redis-password
|
||||||
|
|
||||||
|
## Section: GKE
|
||||||
|
# Settings that make running on Google Kubernetes Engine easier
|
||||||
|
gke:
|
||||||
|
# The CloudSQL Proxy runs as a container in the Fleet Pod that proxies connections to a Cloud SQL instance
|
||||||
|
cloudSQL:
|
||||||
|
enableProxy: false
|
||||||
|
imageTag: 1.17-alpine
|
||||||
|
verbose: true
|
||||||
|
instanceName: ""
|
||||||
|
# The GKE Ingress requires a few changes that other ingress controllers don't
|
||||||
|
ingress:
|
||||||
|
useGKEIngress: false
|
||||||
|
useManagedCertificate: false
|
||||||
|
# Workload Identity allows the K8s service account to assume the IAM permissions of a GCP service account
|
||||||
|
workloadIdentityEmail: ""
|
@ -0,0 +1,170 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
aws = {
|
||||||
|
source = "hashicorp/aws"
|
||||||
|
version = "~> 4.10.0"
|
||||||
|
}
|
||||||
|
random = {
|
||||||
|
source = "hashicorp/random"
|
||||||
|
version = "~> 3.1.2"
|
||||||
|
}
|
||||||
|
mysql = {
|
||||||
|
source = "petoju/mysql"
|
||||||
|
version = "3.0.12"
|
||||||
|
}
|
||||||
|
helm = {
|
||||||
|
source = "hashicorp/helm"
|
||||||
|
version = "2.5.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backend "s3" {}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "helm" {
|
||||||
|
kubernetes {
|
||||||
|
host = data.aws_eks_cluster.cluster.endpoint
|
||||||
|
token = data.aws_eks_cluster_auth.cluster.token
|
||||||
|
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_eks_cluster" "cluster" {
|
||||||
|
name = var.eks_cluster
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_eks_cluster_auth" "cluster" {
|
||||||
|
name = var.eks_cluster
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "mysql" {
|
||||||
|
endpoint = jsondecode(data.aws_secretsmanager_secret_version.mysql.secret_string)["endpoint"]
|
||||||
|
username = jsondecode(data.aws_secretsmanager_secret_version.mysql.secret_string)["username"]
|
||||||
|
password = jsondecode(data.aws_secretsmanager_secret_version.mysql.secret_string)["password"]
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "mysql_secret" {}
|
||||||
|
variable "eks_cluster" {}
|
||||||
|
variable "redis_address" {}
|
||||||
|
variable "redis_database" {}
|
||||||
|
variable "lifecycle_table" {}
|
||||||
|
variable "base_domain" {}
|
||||||
|
|
||||||
|
resource "mysql_user" "main" {
|
||||||
|
user = terraform.workspace
|
||||||
|
host = "%"
|
||||||
|
plaintext_password = random_password.db.result
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "mysql_database" "main" {
|
||||||
|
name = terraform.workspace
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "mysql_grant" "main" {
|
||||||
|
user = mysql_user.main.user
|
||||||
|
database = mysql_database.main.name
|
||||||
|
host = "%"
|
||||||
|
privileges = ["ALL"]
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_secretsmanager_secret_version" "mysql" {
|
||||||
|
secret_id = var.mysql_secret
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "random_password" "db" {
|
||||||
|
length = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "helm_release" "main" {
|
||||||
|
name = terraform.workspace
|
||||||
|
chart = "${path.module}/fleet"
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "fleetName"
|
||||||
|
value = terraform.workspace
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "mysql.password"
|
||||||
|
value = random_password.db.result
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "mysql.createSecret"
|
||||||
|
value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "mysql.secretName"
|
||||||
|
value = terraform.workspace
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "mysql.username"
|
||||||
|
value = mysql_user.main.user
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "mysql.database"
|
||||||
|
value = terraform.workspace
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "mysql.address"
|
||||||
|
value = jsondecode(data.aws_secretsmanager_secret_version.mysql.secret_string)["endpoint"]
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "fleet.tls.enabled"
|
||||||
|
value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "redis.address"
|
||||||
|
value = var.redis_address
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "redis.database"
|
||||||
|
value = var.redis_database
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "kubernetes.io/ingress.class"
|
||||||
|
value = "nginx"
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "hostName"
|
||||||
|
value = "${terraform.workspace}.${var.base_domain}"
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "ingressAnnotations.kubernetes\\.io/ingress\\.class"
|
||||||
|
value = "haproxy"
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "replicas"
|
||||||
|
value = "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "imageTag"
|
||||||
|
value = "v4.17.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_dynamodb_table_item" "main" {
|
||||||
|
table_name = var.lifecycle_table
|
||||||
|
hash_key = "ID"
|
||||||
|
|
||||||
|
item = <<ITEM
|
||||||
|
{
|
||||||
|
"ID": {"S": "${terraform.workspace}"},
|
||||||
|
"State": {"S": "unclaimed"},
|
||||||
|
"redis_db": {"N": "${var.redis_database}"}
|
||||||
|
}
|
||||||
|
ITEM
|
||||||
|
|
||||||
|
depends_on = [helm_release.main]
|
||||||
|
}
|
33
infrastructure/sandbox/PreProvisioner/lambda/go.mod
Normal file
33
infrastructure/sandbox/PreProvisioner/lambda/go.mod
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
module github.com/fleetdm/fleet/infrastructure/demo/PreProvisioner/lambda
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/aws/aws-lambda-go v1.29.0
|
||||||
|
github.com/aws/aws-sdk-go v1.43.37
|
||||||
|
github.com/awslabs/aws-lambda-go-api-proxy v0.13.1
|
||||||
|
github.com/gin-gonic/gin v1.7.7
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
|
github.com/google/uuid v1.3.0
|
||||||
|
github.com/jessevdk/go-flags v1.5.0
|
||||||
|
github.com/otiai10/copy v1.7.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.13.0 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.17.0 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.4.1 // indirect
|
||||||
|
github.com/golang/protobuf v1.4.2 // indirect
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.10 // indirect
|
||||||
|
github.com/leodido/go-urn v1.2.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.1.7 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect
|
||||||
|
google.golang.org/protobuf v1.25.0 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||||
|
)
|
321
infrastructure/sandbox/PreProvisioner/lambda/go.sum
Normal file
321
infrastructure/sandbox/PreProvisioner/lambda/go.sum
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
|
||||||
|
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
|
||||||
|
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||||
|
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
|
||||||
|
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
|
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||||
|
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/aws/aws-lambda-go v1.19.1/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU=
|
||||||
|
github.com/aws/aws-lambda-go v1.29.0 h1:u+sfZkvNBUgt0ZkO8Q/jOMBV22DqMDMbZu04oomM2no=
|
||||||
|
github.com/aws/aws-lambda-go v1.29.0/go.mod h1:aakqVz9vDHhtbt0U2zegh/z9SI2+rJ+yRREZYNQLmWY=
|
||||||
|
github.com/aws/aws-sdk-go v1.43.37 h1:kyZ7UjaPZaCik+asF33UFOOYSwr9liDRr/UM/vuw8yY=
|
||||||
|
github.com/aws/aws-sdk-go v1.43.37/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
|
github.com/awslabs/aws-lambda-go-api-proxy v0.13.1 h1:2hASLXizNyRvrBJPLc7IsNuS7hWhWRTOWOyrCPHdktA=
|
||||||
|
github.com/awslabs/aws-lambda-go-api-proxy v0.13.1/go.mod h1:iAimuKT3RS8Aw99XOMAlaYlhvj7QeuoHxf9gm9NYHLU=
|
||||||
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
|
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||||
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
||||||
|
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
||||||
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||||
|
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||||
|
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||||
|
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||||
|
github.com/go-chi/chi/v5 v5.0.2/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||||
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
|
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||||
|
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||||
|
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||||
|
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||||
|
github.com/gofiber/fiber/v2 v2.1.0/go.mod h1:aG+lMkwy3LyVit4CnmYUbUdgjpc3UYOltvlJZ78rgQ0=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||||
|
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
|
||||||
|
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
|
||||||
|
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
|
||||||
|
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
|
||||||
|
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
|
||||||
|
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
|
||||||
|
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||||
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
||||||
|
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
|
||||||
|
github.com/kataras/golog v0.0.18/go.mod h1:jRYl7dFYqP8aQj9VkwdBUXYZSfUktm+YYg1arJILfyw=
|
||||||
|
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
|
||||||
|
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
|
||||||
|
github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
|
||||||
|
github.com/kataras/pio v0.0.8/go.mod h1:NFfMp2kVP1rmV4N6gH6qgWpuoDKlrOeYi3VrAIWCGsE=
|
||||||
|
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
|
||||||
|
github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
|
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
|
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/labstack/echo/v4 v4.1.17/go.mod h1:Tn2yRQL/UclUalpb5rPdXDevbkJ+lp/2svdyFBg6CHQ=
|
||||||
|
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||||
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||||
|
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.16/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||||
|
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||||
|
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||||
|
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||||
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
|
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||||
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
|
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
|
||||||
|
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
||||||
|
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||||
|
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||||
|
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||||
|
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||||
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
|
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
||||||
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
|
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
|
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
|
||||||
|
github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0=
|
||||||
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
|
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||||
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
|
||||||
|
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
|
||||||
|
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
||||||
|
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
|
||||||
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
|
||||||
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
|
||||||
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
195
infrastructure/sandbox/PreProvisioner/lambda/main.go
Normal file
195
infrastructure/sandbox/PreProvisioner/lambda/main.go
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/aws/aws-lambda-go/lambda"
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||||
|
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
flags "github.com/jessevdk/go-flags"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OptionsStruct struct {
|
||||||
|
LambdaExecutionEnv string `long:"lambda-execution-environment" env:"AWS_EXECUTION_ENV"`
|
||||||
|
LifecycleTable string `long:"dynamodb-lifecycle-table" env:"DYNAMODB_LIFECYCLE_TABLE" required:"true"`
|
||||||
|
MaxInstances int64 `long:"max-instances" env:"MAX_INSTANCES" required:"true"`
|
||||||
|
QueuedInstances int64 `long:"queued-instances" env:"QUEUED_INSTANCES" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = OptionsStruct{}
|
||||||
|
|
||||||
|
type LifecycleRecord struct {
|
||||||
|
ID string
|
||||||
|
State string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInstancesCount() (int64, int64, error) {
|
||||||
|
log.Print("getInstancesCount")
|
||||||
|
svc := dynamodb.New(session.New())
|
||||||
|
// Example iterating over at most 3 pages of a Scan operation.
|
||||||
|
var count, unclaimedCount int64
|
||||||
|
err := svc.ScanPages(
|
||||||
|
&dynamodb.ScanInput{
|
||||||
|
TableName: aws.String(options.LifecycleTable),
|
||||||
|
},
|
||||||
|
func(page *dynamodb.ScanOutput, lastPage bool) bool {
|
||||||
|
log.Print(page)
|
||||||
|
count += *page.Count
|
||||||
|
recs := []LifecycleRecord{}
|
||||||
|
if err := dynamodbattribute.UnmarshalListOfMaps(page.Items, &recs); err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, i := range recs {
|
||||||
|
if i.State == "unclaimed" {
|
||||||
|
unclaimedCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
return count, unclaimedCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type NullEvent struct{}
|
||||||
|
|
||||||
|
func min(a, b int64) int64 {
|
||||||
|
// I really have to implement this myself?
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCmd(args []string) error {
|
||||||
|
cmd := exec.Cmd{
|
||||||
|
Path: "/build/terraform",
|
||||||
|
Dir: "/build/deploy_terraform",
|
||||||
|
Stdout: os.Stdout,
|
||||||
|
Stderr: os.Stderr,
|
||||||
|
Args: append([]string{"/build/terraform"}, args...),
|
||||||
|
}
|
||||||
|
log.Printf("%+v\n", cmd)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func initTerraform() error {
|
||||||
|
err := runCmd([]string{
|
||||||
|
"init",
|
||||||
|
"-backend-config=backend.conf",
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTerraform(workspace string, redis_database int) error {
|
||||||
|
err := runCmd([]string{
|
||||||
|
"workspace",
|
||||||
|
"new",
|
||||||
|
workspace,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = runCmd([]string{
|
||||||
|
"apply",
|
||||||
|
"-auto-approve",
|
||||||
|
"-no-color",
|
||||||
|
"-var",
|
||||||
|
fmt.Sprintf("redis_database=%d", redis_database),
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func idExists(id int) (bool, error) {
|
||||||
|
svc := dynamodb.New(session.New())
|
||||||
|
input := &dynamodb.QueryInput{
|
||||||
|
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
|
||||||
|
":v1": {
|
||||||
|
N: aws.String(fmt.Sprintf("%d", id)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
KeyConditionExpression: aws.String("redis_db = :v1"),
|
||||||
|
TableName: aws.String(options.LifecycleTable),
|
||||||
|
IndexName: aws.String("RedisDatabases"),
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := svc.Query(input)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return *result.Count != 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRedisDatabase() (int, error) {
|
||||||
|
for {
|
||||||
|
ret := rand.Intn(65536)
|
||||||
|
exists, err := idExists(ret)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handler(ctx context.Context, name NullEvent) error {
|
||||||
|
// check if we need to do anything
|
||||||
|
totalCount, unclaimedCount, err := getInstancesCount()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if totalCount >= options.MaxInstances {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if unclaimedCount >= options.QueuedInstances {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
numToReady := min(options.MaxInstances-totalCount, options.QueuedInstances-unclaimedCount)
|
||||||
|
// deploy terraform to initialize everything
|
||||||
|
for i := int64(0); i < numToReady; i++ {
|
||||||
|
if i == 0 {
|
||||||
|
if err := initTerraform(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
redisDatabase, err := getRedisDatabase()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := runTerraform(fmt.Sprintf("t%s", uuid.New().String()[:8]), redisDatabase); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
// Get config from environment
|
||||||
|
parser := flags.NewParser(&options, flags.Default)
|
||||||
|
if _, err = parser.Parse(); err != nil {
|
||||||
|
if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if options.LambdaExecutionEnv == "AWS_Lambda_go1.x" {
|
||||||
|
lambda.Start(handler)
|
||||||
|
} else {
|
||||||
|
if err = handler(context.Background(), NullEvent{}); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
322
infrastructure/sandbox/PreProvisioner/main.tf
Normal file
322
infrastructure/sandbox/PreProvisioner/main.tf
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
docker = {
|
||||||
|
source = "kreuzwerker/docker"
|
||||||
|
version = "~> 2.16.0"
|
||||||
|
}
|
||||||
|
git = {
|
||||||
|
source = "paultyng/git"
|
||||||
|
version = "~> 0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_region" "current" {}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
name = "preprovisioner"
|
||||||
|
full_name = "${var.prefix}-${local.name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_log_group" "main" {
|
||||||
|
name = local.full_name
|
||||||
|
kms_key_id = var.kms_key.arn
|
||||||
|
retention_in_days = 30
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "events-assume-role" {
|
||||||
|
statement {
|
||||||
|
actions = ["sts:AssumeRole"]
|
||||||
|
principals {
|
||||||
|
type = "Service"
|
||||||
|
identifiers = ["events.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "events" {
|
||||||
|
role = aws_iam_role.events.id
|
||||||
|
policy_arn = aws_iam_policy.events.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_policy" "events" {
|
||||||
|
name = "${local.full_name}-events"
|
||||||
|
policy = data.aws_iam_policy_document.events.json
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "events" {
|
||||||
|
statement {
|
||||||
|
actions = ["ecs:RunTask"]
|
||||||
|
resources = [replace(aws_ecs_task_definition.main.arn, "/:\\d+$/", ":*"), replace(aws_ecs_task_definition.main.arn, "/:\\d+$/", "")]
|
||||||
|
condition {
|
||||||
|
test = "ArnLike"
|
||||||
|
variable = "ecs:cluster"
|
||||||
|
values = [var.ecs_cluster.arn]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
actions = ["iam:PassRole"]
|
||||||
|
resources = ["*"]
|
||||||
|
condition {
|
||||||
|
test = "StringLike"
|
||||||
|
variable = "iam:PassedToService"
|
||||||
|
values = ["ecs-tasks.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role" "events" {
|
||||||
|
name = "${local.full_name}-events"
|
||||||
|
path = "/service-role/"
|
||||||
|
|
||||||
|
assume_role_policy = data.aws_iam_policy_document.events-assume-role.json
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "lambda-assume-role" {
|
||||||
|
statement {
|
||||||
|
actions = ["sts:AssumeRole"]
|
||||||
|
principals {
|
||||||
|
type = "Service"
|
||||||
|
identifiers = ["ecs-tasks.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "lambda" {
|
||||||
|
role = aws_iam_role.lambda.id
|
||||||
|
policy_arn = aws_iam_policy.lambda.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "lambda-ecs" {
|
||||||
|
role = aws_iam_role.lambda.id
|
||||||
|
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_policy" "lambda" {
|
||||||
|
name = "${var.prefix}-lambda"
|
||||||
|
policy = data.aws_iam_policy_document.lambda.json
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "lambda" {
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"dynamodb:List*",
|
||||||
|
"dynamodb:DescribeReservedCapacity*",
|
||||||
|
"dynamodb:DescribeLimits",
|
||||||
|
"dynamodb:DescribeTimeToLive"
|
||||||
|
]
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"dynamodb:BatchGet*",
|
||||||
|
"dynamodb:DescribeStream",
|
||||||
|
"dynamodb:DescribeTable",
|
||||||
|
"dynamodb:Get*",
|
||||||
|
"dynamodb:Query",
|
||||||
|
"dynamodb:Scan",
|
||||||
|
"dynamodb:BatchWrite*",
|
||||||
|
"dynamodb:CreateTable",
|
||||||
|
"dynamodb:Delete*",
|
||||||
|
"dynamodb:Update*",
|
||||||
|
"dynamodb:PutItem"
|
||||||
|
]
|
||||||
|
resources = [var.dynamodb_table.arn]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = [ #tfsec:ignore:aws-iam-no-policy-wildcards
|
||||||
|
"kms:Encrypt*",
|
||||||
|
"kms:Decrypt*",
|
||||||
|
"kms:ReEncrypt*",
|
||||||
|
"kms:GenerateDataKey*",
|
||||||
|
"kms:Describe*"
|
||||||
|
]
|
||||||
|
resources = [aws_kms_key.ecr.arn, var.kms_key.arn]
|
||||||
|
}
|
||||||
|
|
||||||
|
statement {
|
||||||
|
actions = ["*"]
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role" "lambda" {
|
||||||
|
name = local.full_name
|
||||||
|
|
||||||
|
assume_role_policy = data.aws_iam_policy_document.lambda-assume-role.json
|
||||||
|
}
|
||||||
|
|
||||||
|
output "lambda_role" {
|
||||||
|
value = aws_iam_role.lambda
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "lambda" {
|
||||||
|
name = local.full_name
|
||||||
|
description = "security group for ${local.full_name}"
|
||||||
|
vpc_id = var.vpc.vpc_id
|
||||||
|
|
||||||
|
egress {
|
||||||
|
description = "egress to all"
|
||||||
|
from_port = 0
|
||||||
|
to_port = 0
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
ipv6_cidr_blocks = ["::/0"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_eks_cluster" "cluster" {
|
||||||
|
name = var.eks_cluster.eks_cluster_id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_ecs_task_definition" "main" {
|
||||||
|
family = local.full_name
|
||||||
|
network_mode = "awsvpc"
|
||||||
|
requires_compatibilities = ["FARGATE"]
|
||||||
|
execution_role_arn = aws_iam_role.lambda.arn
|
||||||
|
task_role_arn = aws_iam_role.lambda.arn
|
||||||
|
cpu = 1024
|
||||||
|
memory = 4096
|
||||||
|
container_definitions = jsonencode(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name = local.name
|
||||||
|
image = docker_registry_image.main.name
|
||||||
|
mountPoints = []
|
||||||
|
volumesFrom = []
|
||||||
|
essential = true
|
||||||
|
networkMode = "awsvpc"
|
||||||
|
logConfiguration = {
|
||||||
|
logDriver = "awslogs"
|
||||||
|
options = {
|
||||||
|
awslogs-group = aws_cloudwatch_log_group.main.name
|
||||||
|
awslogs-region = data.aws_region.current.name
|
||||||
|
awslogs-stream-prefix = local.full_name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
environment = concat([
|
||||||
|
{
|
||||||
|
name = "TF_VAR_mysql_secret"
|
||||||
|
value = var.mysql_secret.id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "TF_VAR_mysql_cluster_name"
|
||||||
|
value = var.eks_cluster.eks_cluster_id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "TF_VAR_eks_cluster"
|
||||||
|
value = var.eks_cluster.eks_cluster_id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "DYNAMODB_LIFECYCLE_TABLE"
|
||||||
|
value = var.dynamodb_table.id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "TF_VAR_lifecycle_table"
|
||||||
|
value = var.dynamodb_table.id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "TF_VAR_base_domain"
|
||||||
|
value = var.base_domain
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "MAX_INSTANCES"
|
||||||
|
value = "100"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "QUEUED_INSTANCES"
|
||||||
|
value = "20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "TF_VAR_redis_address"
|
||||||
|
value = "${var.redis_cluster.primary_endpoint_address}:6379"
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
])
|
||||||
|
lifecycle {
|
||||||
|
create_before_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_kms_key" "ecr" {
|
||||||
|
deletion_window_in_days = 10
|
||||||
|
enable_key_rotation = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_ecr_repository" "main" {
|
||||||
|
name = "${var.prefix}-lambda"
|
||||||
|
image_tag_mutability = "IMMUTABLE"
|
||||||
|
|
||||||
|
image_scanning_configuration {
|
||||||
|
scan_on_push = true
|
||||||
|
}
|
||||||
|
|
||||||
|
encryption_configuration {
|
||||||
|
encryption_type = "KMS"
|
||||||
|
kms_key = aws_kms_key.ecr.arn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "random_uuid" "main" {
|
||||||
|
keepers = {
|
||||||
|
lambda = data.archive_file.main.output_sha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "local_file" "backend-config" {
|
||||||
|
content = templatefile("${path.module}/lambda/backend-template.conf",
|
||||||
|
{
|
||||||
|
remote_state = var.remote_state
|
||||||
|
})
|
||||||
|
filename = "${path.module}/lambda/deploy_terraform/backend.conf"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "archive_file" "main" {
|
||||||
|
type = "zip"
|
||||||
|
output_path = "${path.module}/.lambda.zip"
|
||||||
|
source_dir = "${path.module}/lambda"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "git_repository" "main" {
|
||||||
|
path = "${path.module}/../../../"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "docker_registry_image" "main" {
|
||||||
|
name = "${aws_ecr_repository.main.repository_url}:${data.git_repository.main.branch}-${random_uuid.main.result}"
|
||||||
|
keep_remotely = true
|
||||||
|
|
||||||
|
build {
|
||||||
|
context = "${path.module}/lambda/"
|
||||||
|
pull_parent = true
|
||||||
|
}
|
||||||
|
|
||||||
|
depends_on = [
|
||||||
|
local_file.backend-config
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_event_rule" "main" {
|
||||||
|
name_prefix = var.prefix
|
||||||
|
schedule_expression = "rate(1 hour)"
|
||||||
|
is_enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_cloudwatch_event_target" "main" {
|
||||||
|
rule = aws_cloudwatch_event_rule.main.name
|
||||||
|
arn = var.ecs_cluster.arn
|
||||||
|
role_arn = aws_iam_role.events.arn
|
||||||
|
ecs_target {
|
||||||
|
task_count = 1
|
||||||
|
task_definition_arn = aws_ecs_task_definition.main.arn
|
||||||
|
launch_type = "FARGATE"
|
||||||
|
network_configuration {
|
||||||
|
subnets = var.vpc.private_subnets
|
||||||
|
security_groups = [aws_security_group.lambda.id]
|
||||||
|
assign_public_ip = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
infrastructure/sandbox/PreProvisioner/outputs.tf
Normal file
3
infrastructure/sandbox/PreProvisioner/outputs.tf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
output "lambda_security_group" {
|
||||||
|
value = aws_security_group.lambda
|
||||||
|
}
|
10
infrastructure/sandbox/PreProvisioner/variables.tf
Normal file
10
infrastructure/sandbox/PreProvisioner/variables.tf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
variable "prefix" {}
|
||||||
|
variable "dynamodb_table" {}
|
||||||
|
variable "vpc" {}
|
||||||
|
variable "remote_state" {}
|
||||||
|
variable "mysql_secret" {}
|
||||||
|
variable "eks_cluster" {}
|
||||||
|
variable "redis_cluster" {}
|
||||||
|
variable "base_domain" {}
|
||||||
|
variable "ecs_cluster" {}
|
||||||
|
variable "kms_key" {}
|
117
infrastructure/sandbox/SharedInfrastructure/alb.tf
Normal file
117
infrastructure/sandbox/SharedInfrastructure/alb.tf
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
resource "aws_lb" "main" {
|
||||||
|
name = var.prefix
|
||||||
|
internal = false
|
||||||
|
load_balancer_type = "application"
|
||||||
|
security_groups = [aws_security_group.lb.id]
|
||||||
|
subnets = var.vpc.public_subnets
|
||||||
|
enable_deletion_protection = true
|
||||||
|
}
|
||||||
|
|
||||||
|
output "lb" {
|
||||||
|
value = aws_lb.main
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "lb" {
|
||||||
|
name = "${var.prefix}-lb"
|
||||||
|
vpc_id = var.vpc.vpc_id
|
||||||
|
description = "${var.prefix}-lb"
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = 80
|
||||||
|
to_port = 80
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = 443
|
||||||
|
to_port = 443
|
||||||
|
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"]
|
||||||
|
ipv6_cidr_blocks = ["::/0"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lb_listener" "main" {
|
||||||
|
load_balancer_arn = aws_lb.main.arn
|
||||||
|
port = "443"
|
||||||
|
protocol = "HTTPS"
|
||||||
|
ssl_policy = "ELBSecurityPolicy-TLS-1-2-Ext-2018-06"
|
||||||
|
certificate_arn = aws_acm_certificate.main.arn
|
||||||
|
|
||||||
|
default_action {
|
||||||
|
type = "forward"
|
||||||
|
target_group_arn = aws_lb_target_group.eks.arn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lb_listener" "redirect" {
|
||||||
|
load_balancer_arn = aws_lb.main.arn
|
||||||
|
port = "80"
|
||||||
|
protocol = "HTTP"
|
||||||
|
|
||||||
|
default_action {
|
||||||
|
type = "redirect"
|
||||||
|
redirect {
|
||||||
|
port = "443"
|
||||||
|
protocol = "HTTPS"
|
||||||
|
status_code = "HTTP_301"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "alb_listener" {
|
||||||
|
value = aws_lb_listener.main
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_acm_certificate" "main" {
|
||||||
|
domain_name = "*.${var.base_domain}"
|
||||||
|
subject_alternative_names = [var.base_domain]
|
||||||
|
validation_method = "DNS"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
create_before_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_acm_certificate_validation" "main" {
|
||||||
|
certificate_arn = aws_acm_certificate.main.arn
|
||||||
|
validation_record_fqdns = [for r in cloudflare_record.cert : r.hostname]
|
||||||
|
}
|
||||||
|
|
||||||
|
data "cloudflare_zone" "main" {
|
||||||
|
name = "fleetdm.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_record" "cert" {
|
||||||
|
for_each = { for o in aws_acm_certificate.main.domain_validation_options.* : o.resource_record_name => o... }
|
||||||
|
zone_id = data.cloudflare_zone.main.id
|
||||||
|
name = replace(each.value[0].resource_record_name, ".fleetdm.com.", "")
|
||||||
|
type = each.value[0].resource_record_type
|
||||||
|
value = replace(each.value[0].resource_record_value, "/.$/", "")
|
||||||
|
ttl = 1
|
||||||
|
proxied = false
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_record" "main" {
|
||||||
|
zone_id = data.cloudflare_zone.main.id
|
||||||
|
name = "sandbox"
|
||||||
|
type = "CNAME"
|
||||||
|
value = aws_lb.main.dns_name
|
||||||
|
proxied = false
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "cloudflare_record" "wildcard" {
|
||||||
|
zone_id = data.cloudflare_zone.main.id
|
||||||
|
name = "*.sandbox"
|
||||||
|
type = "CNAME"
|
||||||
|
value = aws_lb.main.dns_name
|
||||||
|
proxied = false
|
||||||
|
}
|
196
infrastructure/sandbox/SharedInfrastructure/eks.tf
Normal file
196
infrastructure/sandbox/SharedInfrastructure/eks.tf
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
provider "kubernetes" {
|
||||||
|
experiments {
|
||||||
|
manifest_resource = true
|
||||||
|
}
|
||||||
|
host = data.aws_eks_cluster.cluster.endpoint
|
||||||
|
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
|
||||||
|
token = data.aws_eks_cluster_auth.cluster.token
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "helm" {
|
||||||
|
kubernetes {
|
||||||
|
host = data.aws_eks_cluster.cluster.endpoint
|
||||||
|
token = data.aws_eks_cluster_auth.cluster.token
|
||||||
|
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "kubectl" {
|
||||||
|
host = data.aws_eks_cluster.cluster.endpoint
|
||||||
|
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
|
||||||
|
token = data.aws_eks_cluster_auth.cluster.token
|
||||||
|
load_config_file = false
|
||||||
|
apply_retry_count = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
cluster_version = "1.21"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "eks_cluster" {
|
||||||
|
value = module.aws-eks-accelerator-for-terraform
|
||||||
|
}
|
||||||
|
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
kubectl = {
|
||||||
|
source = "gavinbunney/kubectl"
|
||||||
|
version = "1.14.0"
|
||||||
|
}
|
||||||
|
cloudflare = {
|
||||||
|
source = "cloudflare/cloudflare"
|
||||||
|
version = "3.18.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_role" "admin" {
|
||||||
|
name = "admin"
|
||||||
|
}
|
||||||
|
|
||||||
|
module "aws-eks-accelerator-for-terraform" {
|
||||||
|
source = "github.com/aws-samples/aws-eks-accelerator-for-terraform.git"
|
||||||
|
cluster_name = var.prefix
|
||||||
|
|
||||||
|
# EKS Cluster VPC and Subnets
|
||||||
|
vpc_id = var.vpc.vpc_id
|
||||||
|
private_subnet_ids = var.vpc.private_subnets
|
||||||
|
|
||||||
|
# EKS CONTROL PLANE VARIABLES
|
||||||
|
cluster_version = local.cluster_version
|
||||||
|
|
||||||
|
# EKS MANAGED NODE GROUPS
|
||||||
|
managed_node_groups = {
|
||||||
|
mg_4 = {
|
||||||
|
node_group_name = "managed-ondemand"
|
||||||
|
instance_types = ["t3.medium"]
|
||||||
|
subnet_ids = var.vpc.private_subnets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map_roles = concat([for i in var.eks_allowed_roles : {
|
||||||
|
rolearn = i.arn
|
||||||
|
username = i.id
|
||||||
|
groups = ["system:masters"]
|
||||||
|
}], [{
|
||||||
|
rolearn = data.aws_iam_role.admin.arn
|
||||||
|
username = data.aws_iam_role.admin.id
|
||||||
|
groups = ["system:masters"]
|
||||||
|
}])
|
||||||
|
|
||||||
|
fargate_profiles = {
|
||||||
|
default = {
|
||||||
|
fargate_profile_name = "default"
|
||||||
|
fargate_profile_namespaces = [
|
||||||
|
{
|
||||||
|
namespace = "default"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
subnet_ids = flatten([var.vpc.private_subnets])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_eks_cluster" "cluster" {
|
||||||
|
name = module.aws-eks-accelerator-for-terraform.eks_cluster_id
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_eks_cluster_auth" "cluster" {
|
||||||
|
name = module.aws-eks-accelerator-for-terraform.eks_cluster_id
|
||||||
|
}
|
||||||
|
|
||||||
|
module "kubernetes-addons" {
|
||||||
|
source = "github.com/aws-samples/aws-eks-accelerator-for-terraform.git//modules/kubernetes-addons"
|
||||||
|
|
||||||
|
eks_cluster_id = module.aws-eks-accelerator-for-terraform.eks_cluster_id
|
||||||
|
eks_cluster_endpoint = module.aws-eks-accelerator-for-terraform.eks_cluster_endpoint
|
||||||
|
eks_cluster_version = local.cluster_version
|
||||||
|
eks_oidc_provider = module.aws-eks-accelerator-for-terraform.eks_oidc_issuer_url
|
||||||
|
eks_worker_security_group_id = module.aws-eks-accelerator-for-terraform.worker_node_security_group_id
|
||||||
|
|
||||||
|
# EKS Managed Add-ons
|
||||||
|
enable_amazon_eks_vpc_cni = true
|
||||||
|
enable_amazon_eks_coredns = true
|
||||||
|
enable_amazon_eks_kube_proxy = true
|
||||||
|
enable_amazon_eks_aws_ebs_csi_driver = true
|
||||||
|
|
||||||
|
#K8s Add-ons
|
||||||
|
enable_aws_load_balancer_controller = true
|
||||||
|
enable_metrics_server = false
|
||||||
|
enable_cluster_autoscaler = true
|
||||||
|
enable_vpa = true
|
||||||
|
enable_prometheus = false
|
||||||
|
enable_ingress_nginx = false
|
||||||
|
enable_aws_for_fluentbit = false
|
||||||
|
enable_argocd = false
|
||||||
|
enable_fargate_fluentbit = false
|
||||||
|
enable_argo_rollouts = false
|
||||||
|
enable_kubernetes_dashboard = false
|
||||||
|
enable_yunikorn = false
|
||||||
|
|
||||||
|
depends_on = [module.aws-eks-accelerator-for-terraform.managed_node_groups]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "helm_release" "haproxy_ingress" {
|
||||||
|
name = "haproxy-ingress-controller"
|
||||||
|
namespace = "kube-system"
|
||||||
|
|
||||||
|
repository = "https://haproxy-ingress.github.io/charts"
|
||||||
|
chart = "haproxy-ingress"
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "controller.hostNetwork"
|
||||||
|
value = "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "controller.kind"
|
||||||
|
value = "DaemonSet"
|
||||||
|
}
|
||||||
|
|
||||||
|
set {
|
||||||
|
name = "controller.service.type"
|
||||||
|
value = "NodePort"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lb_target_group" "eks" {
|
||||||
|
name = var.prefix
|
||||||
|
port = 80
|
||||||
|
protocol = "HTTP"
|
||||||
|
vpc_id = var.vpc.vpc_id
|
||||||
|
health_check {
|
||||||
|
matcher = "404"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "kubernetes_manifest" "targetgroupbinding" {
|
||||||
|
manifest = {
|
||||||
|
"apiVersion" = "elbv2.k8s.aws/v1beta1"
|
||||||
|
"kind" = "TargetGroupBinding"
|
||||||
|
"metadata" = {
|
||||||
|
"name" = "haproxy"
|
||||||
|
"namespace" = "kube-system"
|
||||||
|
}
|
||||||
|
"spec" = {
|
||||||
|
"targetGroupARN" = aws_lb_target_group.eks.arn
|
||||||
|
"serviceRef" = {
|
||||||
|
"name" = helm_release.haproxy_ingress.name
|
||||||
|
"port" = 80
|
||||||
|
}
|
||||||
|
"targetType" = "instance"
|
||||||
|
"networking" = {
|
||||||
|
"ingress" = [{
|
||||||
|
"from" = [{
|
||||||
|
"securityGroup" = {
|
||||||
|
"groupID" = aws_security_group.lb.id
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
"ports" = [{
|
||||||
|
"protocol" = "TCP"
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
infrastructure/sandbox/SharedInfrastructure/rds.tf
Normal file
95
infrastructure/sandbox/SharedInfrastructure/rds.tf
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
resource "random_password" "database_password" {
|
||||||
|
length = 16
|
||||||
|
special = false
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_kms_key" "main" {
|
||||||
|
description = "${var.prefix}-${random_pet.db_secret_postfix.id}"
|
||||||
|
deletion_window_in_days = 10
|
||||||
|
enable_key_rotation = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "random_pet" "db_secret_postfix" {
|
||||||
|
length = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_secretsmanager_secret" "database_password_secret" {
|
||||||
|
name = "/fleet/database/password/master-2-${random_pet.db_secret_postfix.id}"
|
||||||
|
kms_key_id = aws_kms_key.main.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_secretsmanager_secret_version" "database_password_secret_version" {
|
||||||
|
secret_id = aws_secretsmanager_secret.database_password_secret.id
|
||||||
|
secret_string = random_password.database_password.result
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_secretsmanager_secret" "mysql" {
|
||||||
|
name = "/fleet/database/password/mysql-${random_pet.db_secret_postfix.id}"
|
||||||
|
kms_key_id = aws_kms_key.main.id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "mysql_secret" {
|
||||||
|
value = aws_secretsmanager_secret.mysql
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_secretsmanager_secret_version" "mysql" {
|
||||||
|
secret_id = aws_secretsmanager_secret.mysql.id
|
||||||
|
secret_string = jsonencode({
|
||||||
|
endpoint = module.main.cluster_endpoint
|
||||||
|
username = module.main.cluster_master_username
|
||||||
|
password = module.main.cluster_master_password
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module "main" {
|
||||||
|
source = "terraform-aws-modules/rds-aurora/aws"
|
||||||
|
version = "6.2.0"
|
||||||
|
|
||||||
|
name = var.prefix
|
||||||
|
engine = "aurora-mysql"
|
||||||
|
engine_version = "5.7.mysql_aurora.2.10.0"
|
||||||
|
engine_mode = "serverless"
|
||||||
|
|
||||||
|
storage_encrypted = true
|
||||||
|
master_username = "fleet"
|
||||||
|
master_password = random_password.database_password.result
|
||||||
|
create_random_password = false
|
||||||
|
enable_http_endpoint = false
|
||||||
|
performance_insights_enabled = true
|
||||||
|
|
||||||
|
vpc_id = var.vpc.vpc_id
|
||||||
|
subnets = var.vpc.database_subnets
|
||||||
|
create_security_group = true
|
||||||
|
allowed_security_groups = var.allowed_security_groups
|
||||||
|
allowed_cidr_blocks = ["10.0.0.0/8"]
|
||||||
|
kms_key_id = aws_kms_key.main.arn
|
||||||
|
performance_insights_kms_key_id = aws_kms_key.main.arn
|
||||||
|
|
||||||
|
monitoring_interval = 60
|
||||||
|
|
||||||
|
apply_immediately = true
|
||||||
|
skip_final_snapshot = true
|
||||||
|
|
||||||
|
db_parameter_group_name = aws_db_parameter_group.main.id
|
||||||
|
db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.main.id
|
||||||
|
|
||||||
|
scaling_configuration = {
|
||||||
|
auto_pause = true
|
||||||
|
min_capacity = 2
|
||||||
|
max_capacity = 16
|
||||||
|
seconds_until_auto_pause = 300
|
||||||
|
timeout_action = "ForceApplyCapacityChange"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_db_parameter_group" "main" {
|
||||||
|
name = "${var.prefix}-aurora-db-mysql-parameter-group"
|
||||||
|
family = "aurora-mysql5.7"
|
||||||
|
description = "${var.prefix}-aurora-db-mysql-parameter-group"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_rds_cluster_parameter_group" "main" {
|
||||||
|
name = "${var.prefix}-aurora-mysql-cluster-parameter-group"
|
||||||
|
family = "aurora-mysql5.7"
|
||||||
|
description = "${var.prefix}-aurora-mysql-cluster-parameter-group"
|
||||||
|
}
|
55
infrastructure/sandbox/SharedInfrastructure/redis.tf
Normal file
55
infrastructure/sandbox/SharedInfrastructure/redis.tf
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
resource "aws_elasticache_replication_group" "main" {
|
||||||
|
availability_zones = ["us-east-2a", "us-east-2b", "us-east-2c"]
|
||||||
|
engine = "redis"
|
||||||
|
parameter_group_name = aws_elasticache_parameter_group.main.id
|
||||||
|
subnet_group_name = var.vpc.elasticache_subnet_group_name
|
||||||
|
security_group_ids = [aws_security_group.redis.id]
|
||||||
|
replication_group_id = var.prefix
|
||||||
|
num_cache_clusters = 3
|
||||||
|
node_type = "cache.m6g.large"
|
||||||
|
engine_version = "5.0.6"
|
||||||
|
port = "6379"
|
||||||
|
snapshot_retention_limit = 0
|
||||||
|
automatic_failover_enabled = true
|
||||||
|
at_rest_encryption_enabled = false #tfsec:ignore:aws-elasticache-enable-at-rest-encryption
|
||||||
|
transit_encryption_enabled = false #tfsec:ignore:aws-elasticache-enable-in-transit-encryption
|
||||||
|
apply_immediately = true
|
||||||
|
description = var.prefix
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_elasticache_parameter_group" "main" { #tfsec:ignore:aws-vpc-add-description-to-security-group-rule
|
||||||
|
name = var.prefix
|
||||||
|
family = "redis5.0"
|
||||||
|
|
||||||
|
parameter {
|
||||||
|
name = "client-output-buffer-limit-pubsub-hard-limit"
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
parameter {
|
||||||
|
name = "client-output-buffer-limit-pubsub-soft-limit"
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
parameter {
|
||||||
|
name = "databases"
|
||||||
|
value = "65536"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "redis" { #tfsec:ignore:aws-cloudwatch-log-group-customer-key tfsec:ignore:aws-vpc-add-description-to-security-group
|
||||||
|
name = "${var.prefix}-redis"
|
||||||
|
vpc_id = var.vpc.vpc_id
|
||||||
|
description = "${var.prefix}-redis"
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = 6379
|
||||||
|
to_port = 6397
|
||||||
|
protocol = "TCP"
|
||||||
|
cidr_blocks = var.vpc.private_subnets_cidr_blocks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "redis_cluster" {
|
||||||
|
value = aws_elasticache_replication_group.main
|
||||||
|
}
|
14
infrastructure/sandbox/SharedInfrastructure/variables.tf
Normal file
14
infrastructure/sandbox/SharedInfrastructure/variables.tf
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
variable "prefix" {}
|
||||||
|
|
||||||
|
variable "allowed_security_groups" {
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "eks_allowed_roles" {
|
||||||
|
type = list(any)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "vpc" {}
|
||||||
|
variable "base_domain" {}
|
8
infrastructure/sandbox/backend-prod.conf
Normal file
8
infrastructure/sandbox/backend-prod.conf
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
bucket = "fleet-terraform-state20220408141538466600000002"
|
||||||
|
key = "fleet-cloud-sandbox-prod/sandbox/terraform.tfstate" # This should be set to account_alias/unique_key/terraform.tfstate
|
||||||
|
workspace_key_prefix = "fleet-cloud-sandbox-prod" # This should be set to the account alias
|
||||||
|
region = "us-east-2"
|
||||||
|
encrypt = true
|
||||||
|
kms_key_id = "9f98a443-ffd7-4dbe-a9c3-37df89b2e42a"
|
||||||
|
dynamodb_table = "tf-remote-state-lock"
|
||||||
|
role_arn = "arn:aws:iam::353365949058:role/terraform-fleet-cloud-sandbox-prod"
|
242
infrastructure/sandbox/main.tf
Normal file
242
infrastructure/sandbox/main.tf
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
aws = {
|
||||||
|
source = "hashicorp/aws"
|
||||||
|
version = "~> 4.10.0"
|
||||||
|
}
|
||||||
|
docker = {
|
||||||
|
source = "kreuzwerker/docker"
|
||||||
|
version = "~> 2.16.0"
|
||||||
|
}
|
||||||
|
git = {
|
||||||
|
source = "paultyng/git"
|
||||||
|
version = "~> 0.1.0"
|
||||||
|
}
|
||||||
|
random = {
|
||||||
|
source = "hashicorp/random"
|
||||||
|
version = "~> 3.1.2"
|
||||||
|
}
|
||||||
|
cloudflare = {
|
||||||
|
source = "cloudflare/cloudflare"
|
||||||
|
version = "~> 3.18.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backend "s3" {}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "aws" {
|
||||||
|
region = "us-east-2"
|
||||||
|
default_tags {
|
||||||
|
tags = {
|
||||||
|
environment = "fleet-demo-${terraform.workspace}"
|
||||||
|
terraform = "https://github.com/fleetdm/fleet/tree/main/infrastructure/demo"
|
||||||
|
state = "s3://fleet-loadtesting-tfstate/demo-environment"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
provider "aws" {
|
||||||
|
alias = "replica"
|
||||||
|
region = "us-west-1"
|
||||||
|
default_tags {
|
||||||
|
tags = {
|
||||||
|
environment = "fleet-demo-${terraform.workspace}"
|
||||||
|
terraform = "https://github.com/fleetdm/fleet/tree/main/infrastructure/demo"
|
||||||
|
state = "s3://fleet-loadtesting-tfstate/demo-environment"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "cloudflare" {}
|
||||||
|
|
||||||
|
provider "random" {}
|
||||||
|
|
||||||
|
data "aws_ecr_authorization_token" "token" {}
|
||||||
|
provider "docker" {
|
||||||
|
# Configuration options
|
||||||
|
registry_auth {
|
||||||
|
address = "${data.aws_caller_identity.current.account_id}.dkr.ecr.us-east-2.amazonaws.com"
|
||||||
|
username = data.aws_ecr_authorization_token.token.user_name
|
||||||
|
password = data.aws_ecr_authorization_token.token.password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "git" {}
|
||||||
|
|
||||||
|
data "aws_caller_identity" "current" {}
|
||||||
|
|
||||||
|
data "git_repository" "tf" {
|
||||||
|
path = "${path.module}/../../"
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
prefix = "sandbox-prod"
|
||||||
|
base_domain = "sandbox.fleetdm.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "kms" {
|
||||||
|
statement {
|
||||||
|
actions = ["kms:*"]
|
||||||
|
principals {
|
||||||
|
type = "AWS"
|
||||||
|
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
|
||||||
|
}
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"kms:Encrypt*",
|
||||||
|
"kms:Decrypt*",
|
||||||
|
"kms:ReEncrypt*",
|
||||||
|
"kms:GenerateDataKey*",
|
||||||
|
"kms:Describe*",
|
||||||
|
]
|
||||||
|
resources = ["*"]
|
||||||
|
principals {
|
||||||
|
type = "Service"
|
||||||
|
# TODO hard coded region
|
||||||
|
identifiers = ["logs.us-east-2.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_kms_key" "main" {
|
||||||
|
policy = data.aws_iam_policy_document.kms.json
|
||||||
|
enable_key_rotation = true
|
||||||
|
}
|
||||||
|
|
||||||
|
module "vpc" {
|
||||||
|
source = "terraform-aws-modules/vpc/aws"
|
||||||
|
version = "3.12.0"
|
||||||
|
|
||||||
|
name = local.prefix
|
||||||
|
cidr = "10.11.0.0/16"
|
||||||
|
|
||||||
|
# TODO hard coded AZs
|
||||||
|
azs = ["us-east-2a", "us-east-2b", "us-east-2c"]
|
||||||
|
private_subnets = ["10.11.16.0/20", "10.11.32.0/20", "10.11.48.0/20"]
|
||||||
|
public_subnets = ["10.11.128.0/24", "10.11.129.0/24", "10.11.130.0/24"]
|
||||||
|
database_subnets = ["10.11.131.0/24", "10.11.132.0/24", "10.11.133.0/24"]
|
||||||
|
elasticache_subnets = ["10.11.134.0/24", "10.11.135.0/24", "10.11.136.0/24"]
|
||||||
|
|
||||||
|
create_database_subnet_group = false
|
||||||
|
create_database_subnet_route_table = true
|
||||||
|
|
||||||
|
create_elasticache_subnet_group = true
|
||||||
|
create_elasticache_subnet_route_table = true
|
||||||
|
|
||||||
|
enable_vpn_gateway = false
|
||||||
|
one_nat_gateway_per_az = false
|
||||||
|
|
||||||
|
single_nat_gateway = true
|
||||||
|
enable_nat_gateway = true
|
||||||
|
}
|
||||||
|
|
||||||
|
module "shared-infrastructure" {
|
||||||
|
source = "./SharedInfrastructure"
|
||||||
|
prefix = local.prefix
|
||||||
|
vpc = module.vpc
|
||||||
|
allowed_security_groups = [module.pre-provisioner.lambda_security_group.id]
|
||||||
|
eks_allowed_roles = [module.pre-provisioner.lambda_role, module.jit-provisioner.deprovisioner_role]
|
||||||
|
base_domain = local.base_domain
|
||||||
|
}
|
||||||
|
|
||||||
|
module "pre-provisioner" {
|
||||||
|
source = "./PreProvisioner"
|
||||||
|
prefix = local.prefix
|
||||||
|
vpc = module.vpc
|
||||||
|
kms_key = aws_kms_key.main
|
||||||
|
dynamodb_table = aws_dynamodb_table.lifecycle-table
|
||||||
|
remote_state = module.remote_state
|
||||||
|
mysql_secret = module.shared-infrastructure.mysql_secret
|
||||||
|
eks_cluster = module.shared-infrastructure.eks_cluster
|
||||||
|
redis_cluster = module.shared-infrastructure.redis_cluster
|
||||||
|
ecs_cluster = aws_ecs_cluster.main
|
||||||
|
base_domain = local.base_domain
|
||||||
|
}
|
||||||
|
|
||||||
|
module "jit-provisioner" {
|
||||||
|
source = "./JITProvisioner"
|
||||||
|
prefix = local.prefix
|
||||||
|
vpc = module.vpc
|
||||||
|
kms_key = aws_kms_key.main
|
||||||
|
dynamodb_table = aws_dynamodb_table.lifecycle-table
|
||||||
|
remote_state = module.remote_state
|
||||||
|
mysql_secret = module.shared-infrastructure.mysql_secret
|
||||||
|
eks_cluster = module.shared-infrastructure.eks_cluster
|
||||||
|
redis_cluster = module.shared-infrastructure.redis_cluster
|
||||||
|
alb_listener = module.shared-infrastructure.alb_listener
|
||||||
|
ecs_cluster = aws_ecs_cluster.main
|
||||||
|
base_domain = local.base_domain
|
||||||
|
}
|
||||||
|
|
||||||
|
module "monitoring" {
|
||||||
|
source = "./Monitoring"
|
||||||
|
prefix = local.prefix
|
||||||
|
slack_webhook = var.slack_webhook
|
||||||
|
kms_key = aws_kms_key.main
|
||||||
|
lb = module.shared-infrastructure.lb
|
||||||
|
jitprovisioner = module.jit-provisioner.jitprovisioner
|
||||||
|
deprovisioner = module.jit-provisioner.deprovisioner
|
||||||
|
dynamodb_table = aws_dynamodb_table.lifecycle-table
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_dynamodb_table" "lifecycle-table" {
|
||||||
|
name = "${local.prefix}-lifecycle"
|
||||||
|
billing_mode = "PAY_PER_REQUEST"
|
||||||
|
hash_key = "ID"
|
||||||
|
|
||||||
|
server_side_encryption {
|
||||||
|
enabled = true
|
||||||
|
kms_key_arn = aws_kms_key.main.arn
|
||||||
|
}
|
||||||
|
point_in_time_recovery {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute {
|
||||||
|
name = "ID"
|
||||||
|
type = "S"
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute {
|
||||||
|
name = "State"
|
||||||
|
type = "S"
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute {
|
||||||
|
name = "redis_db"
|
||||||
|
type = "N"
|
||||||
|
}
|
||||||
|
|
||||||
|
global_secondary_index {
|
||||||
|
name = "RedisDatabases"
|
||||||
|
hash_key = "redis_db"
|
||||||
|
projection_type = "KEYS_ONLY"
|
||||||
|
}
|
||||||
|
global_secondary_index {
|
||||||
|
name = "FleetState"
|
||||||
|
hash_key = "State"
|
||||||
|
projection_type = "ALL"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module "remote_state" {
|
||||||
|
source = "nozaq/remote-state-s3-backend/aws"
|
||||||
|
tags = {}
|
||||||
|
|
||||||
|
providers = {
|
||||||
|
aws = aws
|
||||||
|
aws.replica = aws.replica
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_ecs_cluster" "main" {
|
||||||
|
name = local.prefix
|
||||||
|
|
||||||
|
setting {
|
||||||
|
name = "containerInsights"
|
||||||
|
value = "enabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "slack_webhook" {}
|
15
infrastructure/sandbox/readme.md
Normal file
15
infrastructure/sandbox/readme.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
## Terraform for the Fleet Demo Environment
|
||||||
|
This folder holds the infrastructure code for Fleet's demo environment. See https://github.com/fleetdm/fleet-infra/pull/3 for design documentation.
|
||||||
|
|
||||||
|
The interface into this code is designed to be minimal.
|
||||||
|
If you require changes beyond whats described here, contact @zwinnerman-fleetdm.
|
||||||
|
|
||||||
|
### Deploying your code to the loadtesting environment
|
||||||
|
1. Initialize your terraform environment with `terraform init`
|
||||||
|
2. Check out the appropiate workspace for your code, for instance `terraform workspace select production`
|
||||||
|
3. Apply terraform with your branch name with `terraform apply -var tag=BRANCH_NAME -var-file production.tfvars`
|
||||||
|
|
||||||
|
### Bugs
|
||||||
|
1. module.shared-infrastructure.kubernetes_manifest.targetgroupbinding is bugged sometimes, if it gives issues just comment it out
|
||||||
|
1. on a fresh apply, module.shared-infrastructure.aws_acm_certificate.main will have to be targeted first, then a normal apply can follow
|
||||||
|
1. If errors happen, see if applying again will fix it
|
Loading…
Reference in New Issue
Block a user