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