Self Hosted Installation on AWS EKS
To install and run a self-hosted Mission Control on AWS EKS you need to have the following prerequisites:
- EKS 1.28+ with an Ingress Controller
- 500m - 2000m of CPU and 6 - 8GB of Memory (2 - 4GB if using an external DB)
- Persistent Volumes with 20GB+ of storage or an external postgres database like RDS
- Access to create
- (Optional) SMTP Server (For sending notifications and invites)
Create an IAM Role
Depending on how you want to use Mission Control you need to create an IAM role for mission control to use:
Use Case | Role |
---|---|
Read Only Scraping | arn:aws:iam::aws:policy/ReadOnlyAccess |
Playbooks to create and update AWS Resources | arn:aws:iam::aws:policy/PowerUserAccess |
Create new IAM Policy (Alternative)
You can also create a new policy with just the permissions required by Mission Control
iam-policy.json{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "mission-control-config-role",
"Effect": "Allow",
"Action": [
"acm:Describe*",
"acm:Get*",
"acm:List*",
"cloudtrail:LookupEvents",
"config:BatchGetAggregateResourceConfig",
"config:BatchGetResourceConfig",
"config:Describe*",
"config:Get*",
"config:List*",
"config:SelectAggregateResourceConfig",
"config:SelectResourceConfig",
"ec2:Describe*",
"ecr:Describe*",
"eks:Describe*",
"eks:ListClusters",
"elasticfilesystem:Describe*",
"elasticloadbalancing:Describe*",
"guardduty:Describe*",
"guardduty:Get*",
"guardduty:List*",
"iam:GetAccountName",
"iam:GetAccountSummary",
"iam:GetGroup",
"iam:GetGroupPolicy",
"iam:GetInstanceProfile",
"iam:GetLoginProfile",
"iam:GetPolicy",
"iam:GetRole",
"iam:GetRolePolicy",
"iam:GetUser",
"iam:List*",
"lambda:List*",
"rds:Describe*",
"sts:GetCallerIdentity"
"trustedadvisor:Describe*",
"trustedadvisor:DownloadRisk",
"trustedadvisor:Get*",
"trustedadvisor:List*",
],
"Resource": "*"
}
]
}
Configure IAM Roles for Mission Control
- IAM Roles for Service Accounts
- Pod Identity
- Access Key
- eksctl
-
Setup variables
# The name of the EKS cluster mission control is being deployed to
export CLUSTER= <CLUSTER_NAME>
# the default namespace the mission-control helm chart uses
export NAMESPACE=mission-control
export ACCOUNT=$(aws sts get-caller-identity --query 'Account' --output text) -
Enable EKS IAM Roles for Service Accounts
eksctl utils associate-iam-oidc-provider --cluster=$CLUSTER
-
Create the IAM Role mappings
eksctl.yamliam:
withOIDC: true
serviceAccounts:
- metadata:
name: mission-control-sa
namespace: mission-control
roleName: MissionControlRole
roleOnly: true
attachPolicyARNs:
- "arn:aws:iam::aws:policy/ReadOnlyAccess"
- metadata:
name: canary-checker-sa
namespace: mission-control
roleName: CanaryCheckerRole
roleOnly: true
attachPolicyARNs:
- "arn:aws:iam::aws:policy/ReadOnlyAccess"
- metadata:
name: config-db-sa
namespace: mission-control
roleName: ConfigDBRole
roleOnly: true
attachPolicyARNs:
- "arn:aws:iam::aws:policy/ReadOnlyAccess"eksctl create iamserviceaccount --cluster $CLUSTER -c eksctl.yaml
-
Choose a routable
DOMAIN
for Mission ControlSee Ingress for more options on configuring the ingress including generating certs with cert-manager
See Local Testing for testing using a kind or minikube without a routable domain
-
Install Mission Control
See values.yaml- Helm
- Flux
cat > values.yaml << EOF
serviceAccount:
annotations:
# used by mission control for notifications / playbooks
eks.amazonaws.com/role-arn: arn:aws:iam::$ACCOUNT:role/MissionControlRole
canary-checker:
serviceAccount:
annotations:
# used for cloudwatch, S3 and other AWS health checks
eks.amazonaws.com/role-arn: arn:aws:iam::$ACCOUNT:role/CanaryCheckerRole
config-db:
serviceAccount:
annotations:
# used to scrape AWS resources, change history via AWS CloudTrail and cost via Athena
eks.amazonaws.com/role-arn: arn:aws:iam::$ACCOUNT:role/ConfigDBRole
EOF
helm repo add flanksource https://flanksource.github.io/charts
helm repo update
helm install mission-control flanksource/mission-control \
--set global.ui.host=DOMAIN \
--set-file values.yaml \
-n mission-control --create-namespace \
--waitapiVersion: v1
kind: Namespace
metadata:
name: mission-control
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: flanksource
namespace: mission-control
spec:
interval: 5m0s
url: https://flanksource.github.io/charts
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: mission-control
namespace: mission-control
spec:
chart:
spec:
chart: mission-control
sourceRef:
kind: HelmRepository
name: flanksource
namespace: mission-control
interval: 1m
values:
serviceAccount:
annotations:
# used by mission control for notifications / playbooks
eks.amazonaws.com/role-arn: arn:aws:iam::$ACCOUNT:role/MissionControlRole
canary-checker:
serviceAccount:
annotations:
# used for cloudwatch, S3 and other AWS health checks
eks.amazonaws.com/role-arn: arn:aws:iam::$ACCOUNT:role/CanaryCheckerRole
config-db:
serviceAccount:
annotations:
# used to scrape AWS resources, change history via AWS CloudTrail and cost via Athena
eks.amazonaws.com/role-arn: arn:aws:iam::$ACCOUNT:role/ConfigDBRole
global.ui.host: DOMAIN
- eksctl
- Terraform
- Cloudformation
-
Ensure the AWS Pod Identity Agent is configured and running
-
Create a mapping file for
eksctl
eksctl.yamlpodIdentityAssociations:
- namespace: mission-control
serviceAccountName: mission-control-sa
permissionPolicyARNs: arn:aws:iam::aws:policy/ReadOnlyAccess
- namespace: mission-control
serviceAccountName: config-db-sa
permissionPolicyARNs: arn:aws:iam::aws:policy/ReadOnlyAccess
- namespace: mission-control
serviceAccountName: canary-checker-sa
permissionPolicyARNs: arn:aws:iam::aws:policy/ReadOnlyAccess
iam:
# note withOIDC is not required for Pod Identity
serviceAccounts:
# used by mission control for notifications / playbooks
- metadata:
name: mission-control-sa
namespace: mission-control
attachPolicyARNs:
- "arn:aws:iam::aws:policy/ReadOnlyAccess"
# used for cloudwatch, S3 and other AWS health checks
- metadata:
name: canary-checker-sa
namespace: mission-control
attachPolicyARNs:
- "arn:aws:iam::aws:policy/ReadOnlyAccess"
# used to scrape resources, AWS CloudTrail and AWS Cost & Usage Reports
- metadata:
name: config-db-sa
namespace: mission-control
attachPolicyARNs:
- "arn:aws:iam::aws:policy/ReadOnlyAccess"Using an existing IAM Role
If you are using a pre-existing IAM role when creating a pod identity association, you must configure the role to trust the newly introduced EKS service principal (
pods.eks.amazonaws.com
)iam-trust-policy.json{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": ["sts:AssumeRole", "sts:TagSession"]
}
]
} -
Apply the Pod Identities using
eksctl
eksctl create podidentityassociation -c eksctl.yaml
-
Choose a routable
DOMAIN
for Mission ControlSee Ingress for more options on configuring the ingress including generating certs with cert-manager
See Local Testing for testing using a kind or minikube without a routable domain
-
Install Mission Control
See values.yaml- Helm
- Flux
helm repo add flanksource https://flanksource.github.io/charts
helm repo update
helm install mission-control flanksource/mission-control \
--set global.ui.host=DOMAIN \
-n mission-control --create-namespace \
--waitapiVersion: v1
kind: Namespace
metadata:
name: mission-control
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: flanksource
namespace: mission-control
spec:
interval: 5m0s
url: https://flanksource.github.io/charts
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: mission-control
namespace: mission-control
spec:
chart:
spec:
chart: mission-control
sourceRef:
kind: HelmRepository
name: flanksource
namespace: mission-control
interval: 1m
values:
global.ui.host: DOMAIN
-
Ensure the AWS Pod Identity Agent is configured and running
-
Create
main.tf
main.tfvariable "cluster" {
type = string
}
variable "role" {
type = string
}
variable "namespace" {
type = string
default = "mission-control"
}
variable "policy" {
type = string
default = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}
locals {
service_accounts = [
"mission-control-sa",
"canary-checker-sa",
"config-db-sa"
]
}
data "aws_caller_identity" "current" {}
resource "aws_iam_role" "mission-control" {
name = "MissionControlRole"
assume_role_policy = jsonencode({
Statement = [{
Action = [
"sts:AssumeRole",
"sts:TagSession"
]
Effect = "Allow"
Principal = {
Service: "pods.eks.amazonaws.com"
}
}]
Version = "2012-10-17"
})
}
resource "aws_iam_role_policy_attachment" "mission-control" {
policy_arn = var.policy
role = aws_iam_role.mission-control.name
}
resource "aws_eks_pod_identity_association" "pod_identities" {
for_each = local.service_accounts
cluster_name = var.cluster
namespace = var.namespace
service_account = each.value
role_arn = var.role
} -
Apply the terraform
TF_VAR_role=$CLUSTER terraform apply
-
Choose a routable
DOMAIN
for Mission ControlSee Ingress for more options on configuring the ingress including generating certs with cert-manager
See Local Testing for testing using a kind or minikube without a routable domain
-
Install Mission Control
See values.yaml- Helm
- Flux
helm repo add flanksource https://flanksource.github.io/charts
helm repo update
helm install mission-control flanksource/mission-control \
--set global.ui.host=DOMAIN \
-n mission-control --create-namespace \
--waitapiVersion: v1
kind: Namespace
metadata:
name: mission-control
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: flanksource
namespace: mission-control
spec:
interval: 5m0s
url: https://flanksource.github.io/charts
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: mission-control
namespace: mission-control
spec:
chart:
spec:
chart: mission-control
sourceRef:
kind: HelmRepository
name: flanksource
namespace: mission-control
interval: 1m
values:
global.ui.host: DOMAIN
-
Setup variables
# The name of the EKS cluster mission control is being deployed to
export CLUSTER= <CLUSTER_NAME>
# the default namespace the mission-control helm chart uses
export NAMESPACE=mission-control -
Create a cloudformation template
mission-control-iam-cloudformation.yamlAWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for Mission Control IAM Role using EKS Pod Identities
Parameters:
Cluster:
Type: String
Description: Name of the EKS cluster
Namespace:
Type: String
Default: "mission-control"
Description: Kubernetes namespace
PolicyArn:
Type: String
Default: "arn:aws:iam::aws:policy/ReadOnlyAccess"
Description: ARN of the IAM policy to attach to the role
Resources:
MissionControlRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: "MissionControlRole"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service: "eks.amazonaws.com"
Action:
- "sts:AssumeRole"
- "sts:TagSession"
MissionControlRolePolicyAttachment:
Type: "AWS::IAM::Policy"
Properties:
PolicyName: "MissionControlPolicy"
Roles:
- Ref: "MissionControlRole"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "*"
Resource: "*"
MissionControlServiceAccount:
Type: "AWS::EKS::PodIdentityAssociation"
Properties:
ClusterName: !Ref "Cluster"
Namespace: !Ref "Namespace"
RoleArn: !GetAtt MissionControlRole.Arn
ServiceAccount: mission-control-sa
CanaryCheckerServiceAccount:
Type: "AWS::EKS::PodIdentityAssociation"
Properties:
ClusterName: !Ref "Cluster"
Namespace: !Ref "Namespace"
RoleArn: !GetAtt MissionControlRole.Arn
ServiceAccount: canary-checker-sa
ConfigDBServiceAccount:
Type: "AWS::EKS::PodIdentityAssociation"
Properties:
ClusterName: !Ref "Cluster"
Namespace: !Ref "Namespace"
RoleArn: !GetAtt MissionControlRole.Arn
ServiceAccount: config-db-sa -
Create a new stack
aws cloudformation deploy \
--stack-name mission-control-roles \
--template-file file://mission-control-iam-cloudformation.yaml \
--parameter-overrides Cluster==$CLUSTER Namespace=$NAMESPACE -
Choose a routable
DOMAIN
for Mission ControlSee Ingress for more options on configuring the ingress including generating certs with cert-manager
See Local Testing for testing using a kind or minikube without a routable domain
-
Install Mission Control
See values.yaml- Helm
- Flux
helm repo add flanksource https://flanksource.github.io/charts
helm repo update
helm install mission-control flanksource/mission-control \
--set global.ui.host=DOMAIN \
-n mission-control --create-namespace \
--waitapiVersion: v1
kind: Namespace
metadata:
name: mission-control
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: flanksource
namespace: mission-control
spec:
interval: 5m0s
url: https://flanksource.github.io/charts
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: mission-control
namespace: mission-control
spec:
chart:
spec:
chart: mission-control
sourceRef:
kind: HelmRepository
name: flanksource
namespace: mission-control
interval: 1m
values:
global.ui.host: DOMAIN
Using Access Keys and Secrets is not recommended from a security perspective
First we create a secret called aws
containing the access key and secret.
-
Choose a routable
DOMAIN
for Mission ControlSee Ingress for more options on configuring the ingress including generating certs with cert-manager
See Local Testing for testing using a kind or minikube without a routable domain
-
Install Mission Control
See values.yaml- Helm
- Flux
helm repo add flanksource https://flanksource.github.io/charts
helm repo update
helm install mission-control flanksource/mission-control \
--set global.ui.host=DOMAIN \
-n mission-control --create-namespace \
--waitapiVersion: v1
kind: Namespace
metadata:
name: mission-control
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: flanksource
namespace: mission-control
spec:
interval: 5m0s
url: https://flanksource.github.io/charts
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: mission-control
namespace: mission-control
spec:
chart:
spec:
chart: mission-control
sourceRef:
kind: HelmRepository
name: flanksource
namespace: mission-control
interval: 1m
values:
global.ui.host: DOMAIN -
Create a new IAM User and Access Key
USER_NAME="mission-control-sa"
aws iam create-user --user-name $USER_NAME
aws iam attach-user-policy \
--user-name $USER_NAME \
--policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess
key=$(aws iam create-access-key --user-name $USER_NAME) -
Create a new secret
aws
containing the access and secret keykubectl create secret generic aws \
--from-literal=AWS_ACCESS_KEY_ID=$(echo $key | jq -r '.AccessKey.AccessKeyId') \
--from-literal=AWS_SECRET_ACCESS_KEY=$(echo $key | jq -r '.AccessKey.SecretAccessKey') -
Create a new connection
aws-connection.yamlapiVersion: mission-control.flanksource.com/v1
kind: Connection
metadata:
name: aws
namespace: mission-control
spec:
region: eu-west-1
accessKey:
valueFrom:
secretKeyRef:
name: aws
key: AWS_ACCESS_KEY_ID
secretKey:
valueFrom:
secretKeyRef:
name: aws
key: AWS_ACCESS_KEY_ID -
When creating Scrapers / Registry bundles you can now refer to
connection://mission-control/aws
Next Steps
Install the AWS registry chart to configure the AWS Scraper