using System.Collections.Generic;
using System.Linq;
using Amazon.CDK;
using Amazon.CDK.AWS.EKS;
using Amazon.CDK.AWS.IAM;
namespace CdkShared
{
public static class Eks
{
public static string[] DefaultK8sNamespaces => new [] { "default", "kube-system", "kube-public" };
public static bool IsStandardNamespace(string namespaceName)
=> DefaultK8sNamespaces.Contains(namespaceName);
///
/// Creates K8s namespace if namespace name is not "default", "kube-system", or "kube-public"
///
///
///
/// Optional namespace labels
///
public static KubernetesManifest AddNamespaceIfNecessary(this ICluster eksCluster, string namespaceName, Dictionary labels = null)
{
return IsStandardNamespace(namespaceName) ? null : eksCluster.AddNamespace(namespaceName, labels);
}
public static ServiceAccount AddServiceAccount(this ICluster eksCluster, string name,
string k8sNamespace, IDependable dependency)
{
ServiceAccount svcAccount = eksCluster.AddServiceAccount($"svc-account-{name}-{k8sNamespace}", new ServiceAccountOptions
{
Name = name,
Namespace = k8sNamespace
});
if(dependency != null)
svcAccount.Node.AddDependency(dependency);
return svcAccount;
}
public static ServiceAccount AddServiceAccount(this ICluster eksCluster, string name,
string k8sNamespace, IDependable dependency, params string[] managedIamPolicyNames)
{
var svcAccount = eksCluster.AddServiceAccount(name, k8sNamespace, dependency);
foreach (string managedPolicyName in managedIamPolicyNames)
{
svcAccount.Role.AddManagedPolicy(ManagedPolicy.FromAwsManagedPolicyName(managedPolicyName));
}
return svcAccount;
}
public static ServiceAccount AddServiceAccount(this ICluster eksCluster, string name,
string k8sNamespace, IDependable dependency, params PolicyStatement[] policyStatements)
{
var svcAccount = eksCluster.AddServiceAccount(name, k8sNamespace, dependency);
foreach (var iamPolicyStatement in policyStatements)
{
svcAccount.AddToPrincipalPolicy(iamPolicyStatement);
}
return svcAccount;
}
///
/// Installs AWS App Mesh Controller - an add-on integrating Kubernetes cluster with AWS App Mesh.
///
///
/// K8s namespace where AWS App Mesh controller will be installed
/// Set to true to enable AWS X-Ray side-car container
///
public static HelmChart AddAppMeshController(this ICluster eksCluster,
string appMeshControllerNamespace = "appmesh-system",
bool traceWithXRayOnAppMesh = true)
{
// Create K8s namespace if installing the controller in non-default/kube-system namespace
var amcNamespace = eksCluster.AddNamespaceIfNecessary(appMeshControllerNamespace);
// Create K8s service account for the controller. This service account will be mapped to AWS IAM Roles
// letting controller interface with AWS services to do its job.
ServiceAccount svcAccount = eksCluster.AddServiceAccount("appmesh-controller", appMeshControllerNamespace,
amcNamespace, "AWSCloudMapFullAccess", "AWSAppMeshFullAccess");
// Set Helm chart parameters
var chartValues = new Dictionary
{
["region"] = eksCluster.Stack.Region,
["serviceAccount"] = new Dictionary
{
["create"] = false,
["name"] = svcAccount.ServiceAccountName
}
};
// If X-Ray tracing enabled via parameters, turn X-Ray on via helm chart params.
if (traceWithXRayOnAppMesh)
chartValues.Add("tracing", new Dictionary
{
["enabled"] = true,
["provider"] = "x-ray"
});
// Run the Helm Chart installing App Mesh controller
// Note that Helm release "app-mesh-by-cdk" will be accessible using "helm list" command
HelmChart chart = eksCluster.AddHelmChart("appmesh-controller", new HelmChartProps
{
Repository = "https://aws.github.io/eks-charts",
Chart = "appmesh-controller",
Release = "app-mesh-by-cdk",
Namespace = appMeshControllerNamespace,
Values = chartValues
});
chart.Node.AddDependency(svcAccount);
return chart;
}
///
/// Installs AWS Load Balancer Controller to let outside traffic into the cluster via AWS Application Load Balancer.
///
///
///
///
public static HelmChart AddAwsLoadBalancerController(this ICluster eksCluster,
string lbControllerNamespace = "kube-system")
{
KubernetesManifest lbcNamespace = eksCluster.AddNamespaceIfNecessary(lbControllerNamespace);
ServiceAccount svcAccount = eksCluster.CreateLbControllerServiceAccount(lbControllerNamespace, lbcNamespace);
// Runs Helm chart installing AWS LB controller.
// The manifest will be accessible via "helm list" on the system where "cdk deploy" was run.
HelmChart chart = eksCluster.AddHelmChart("aws-load-balancer-controller-chart", new HelmChartOptions
{
Repository = "https://aws.github.io/eks-charts",
Chart = "aws-load-balancer-controller",
Release = "aws-lb-controller-by-cdk",
Namespace = lbControllerNamespace,
Values = new Dictionary
{
["fullnameOverride"] = "aws-lb-controller",
["clusterName"] = eksCluster.ClusterName,
["serviceAccount"] = new Dictionary
{
["create"] = false,
["name"] = svcAccount.ServiceAccountName,
},
["vpcId"] = eksCluster.Vpc.VpcId,
["region"] = eksCluster.Stack.Region
}
});
chart.Node.AddDependency(svcAccount);
return chart;
}
///
/// Creates K8s service account for AWS LB Controller to run under.
/// Attaches appropriate IAM policies to the service account to let AWS LB Controller do its job.
///
///
/// K8s namespace where ALB Ingress Controller will be installed
///
private static ServiceAccount CreateLbControllerServiceAccount(this ICluster eksCluster, string k8sNamespace, KubernetesManifest lbcNamespace)
{
IEnumerable