Implement EKS support [#5]

I *think* this will work, but without access to an EKS cluster I can't
actually test it.
This commit is contained in:
Erin Call
2019-12-27 10:39:06 -08:00
parent d8d2e33b20
commit 9c1ed849ab
7 changed files with 68 additions and 3 deletions

View File

@@ -30,7 +30,9 @@ Installations are triggered when the `helm_command` setting is "upgrade." They c
| chart | string | yes | The chart to use for this installation. | | chart | string | yes | The chart to use for this installation. |
| release | string | yes | The release name for helm to use. | | release | string | yes | The release name for helm to use. |
| api_server | string | yes | API endpoint for the Kubernetes cluster. | | api_server | string | yes | API endpoint for the Kubernetes cluster. |
| kubernetes_token | string | yes | Token for authenticating to Kubernetes. | | kubernetes_token | string | yes, unless using EKS | Token for authenticating to Kubernetes. |
| eks_cluster | string | | AWS EKS cluster ID. |
| eks_role_arn | string | | AWS IAM role ARN for EKS authentication. |
| service_account | string | | Service account for authenticating to Kubernetes. Default is `helm`. | | service_account | string | | Service account for authenticating to Kubernetes. Default is `helm`. |
| kubernetes_certificate | string | | Base64 encoded TLS certificate used by the Kubernetes cluster's certificate authority. | | kubernetes_certificate | string | | Base64 encoded TLS certificate used by the Kubernetes cluster's certificate authority. |
| chart_version | string | | Specific chart version to install. | | chart_version | string | | Specific chart version to install. |
@@ -52,7 +54,9 @@ Uninstallations are triggered when the `helm_command` setting is "uninstall" or
|------------------------|----------|----------|---------| |------------------------|----------|----------|---------|
| release | string | yes | The release name for helm to use. | | release | string | yes | The release name for helm to use. |
| api_server | string | yes | API endpoint for the Kubernetes cluster. | | api_server | string | yes | API endpoint for the Kubernetes cluster. |
| kubernetes_token | string | yes | Token for authenticating to Kubernetes. | | kubernetes_token | string | yes, unless using EKS | Token for authenticating to Kubernetes. |
| eks_cluster | string | | AWS EKS cluster ID. |
| eks_role_arn | string | | AWS IAM role ARN for EKS authentication. |
| service_account | string | | Service account for authenticating to Kubernetes. Default is `helm`. | | service_account | string | | Service account for authenticating to Kubernetes. Default is `helm`. |
| kubernetes_certificate | string | | Base64 encoded TLS certificate used by the Kubernetes cluster's certificate authority. | | kubernetes_certificate | string | | Base64 encoded TLS certificate used by the Kubernetes cluster's certificate authority. |
| dry_run | boolean | | Pass `--dry-run` to `helm uninstall`. | | dry_run | boolean | | Pass `--dry-run` to `helm uninstall`. |

View File

@@ -23,6 +23,8 @@ type Config struct {
ValuesFiles []string `split_words:"true"` // Arguments to pass to --values in applicable helm commands ValuesFiles []string `split_words:"true"` // Arguments to pass to --values in applicable helm commands
Namespace string `` // Kubernetes namespace for all helm commands Namespace string `` // Kubernetes namespace for all helm commands
KubeToken string `envconfig:"KUBERNETES_TOKEN"` // Kubernetes authentication token to put in .kube/config KubeToken string `envconfig:"KUBERNETES_TOKEN"` // Kubernetes authentication token to put in .kube/config
EKSCluster string `envconfig:"EKS_CLUSTER"` // AWS EKS Cluster ID to put in .kube/config
EKSRoleARN string `envconfig:"EKS_ROLE_ARN"` // AWS IAM role resource name to put in .kube/config
SkipTLSVerify bool `envconfig:"SKIP_TLS_VERIFY"` // Put insecure-skip-tls-verify in .kube/config SkipTLSVerify bool `envconfig:"SKIP_TLS_VERIFY"` // Put insecure-skip-tls-verify in .kube/config
Certificate string `envconfig:"KUBERNETES_CERTIFICATE"` // The Kubernetes cluster CA's self-signed certificate (must be base64-encoded) Certificate string `envconfig:"KUBERNETES_CERTIFICATE"` // The Kubernetes cluster CA's self-signed certificate (must be base64-encoded)
APIServer string `envconfig:"API_SERVER"` // The Kubernetes cluster's API endpoint APIServer string `envconfig:"API_SERVER"` // The Kubernetes cluster's API endpoint

View File

@@ -142,6 +142,8 @@ func initKube(cfg Config) []Step {
APIServer: cfg.APIServer, APIServer: cfg.APIServer,
ServiceAccount: cfg.ServiceAccount, ServiceAccount: cfg.ServiceAccount,
Token: cfg.KubeToken, Token: cfg.KubeToken,
EKSCluster: cfg.EKSCluster,
EKSRoleARN: cfg.EKSRoleARN,
TemplateFile: kubeConfigTemplate, TemplateFile: kubeConfigTemplate,
ConfigFile: kubeConfigFile, ConfigFile: kubeConfigFile,
}, },

View File

@@ -212,6 +212,8 @@ func (suite *PlanTestSuite) TestInitKube() {
Certificate: "b2Ygd29rZW5lc3MK", Certificate: "b2Ygd29rZW5lc3MK",
APIServer: "123.456.78.9", APIServer: "123.456.78.9",
ServiceAccount: "helmet", ServiceAccount: "helmet",
EKSCluster: "eks_reader",
EKSRoleARN: "arn:aws:iam::9631085:role/eksSpangleRole",
} }
steps := initKube(cfg) steps := initKube(cfg)
@@ -225,6 +227,8 @@ func (suite *PlanTestSuite) TestInitKube() {
APIServer: "123.456.78.9", APIServer: "123.456.78.9",
ServiceAccount: "helmet", ServiceAccount: "helmet",
Token: "cXVlZXIgY2hhcmFjdGVyCg==", Token: "cXVlZXIgY2hhcmFjdGVyCg==",
EKSCluster: "eks_reader",
EKSRoleARN: "arn:aws:iam::9631085:role/eksSpangleRole",
TemplateFile: kubeConfigTemplate, TemplateFile: kubeConfigTemplate,
ConfigFile: kubeConfigFile, ConfigFile: kubeConfigFile,
} }

View File

@@ -15,6 +15,8 @@ type InitKube struct {
APIServer string APIServer string
ServiceAccount string ServiceAccount string
Token string Token string
EKSCluster string
EKSRoleARN string
TemplateFile string TemplateFile string
ConfigFile string ConfigFile string
@@ -30,6 +32,8 @@ type kubeValues struct {
Namespace string Namespace string
ServiceAccount string ServiceAccount string
Token string Token string
EKSCluster string
EKSRoleARN string
} }
// Execute generates a kubernetes config file from drone-helm3's template. // Execute generates a kubernetes config file from drone-helm3's template.
@@ -48,9 +52,12 @@ func (i *InitKube) Prepare(cfg Config) error {
if i.APIServer == "" { if i.APIServer == "" {
return errors.New("an API Server is needed to deploy") return errors.New("an API Server is needed to deploy")
} }
if i.Token == "" { if i.Token == "" && i.EKSCluster == "" {
return errors.New("token is needed to deploy") return errors.New("token is needed to deploy")
} }
if i.Token != "" && i.EKSCluster != "" {
return errors.New("token cannot be used simultaneously with eksCluster")
}
if i.ServiceAccount == "" { if i.ServiceAccount == "" {
i.ServiceAccount = "helm" i.ServiceAccount = "helm"
@@ -70,6 +77,8 @@ func (i *InitKube) Prepare(cfg Config) error {
APIServer: i.APIServer, APIServer: i.APIServer,
ServiceAccount: i.ServiceAccount, ServiceAccount: i.ServiceAccount,
Token: i.Token, Token: i.Token,
EKSCluster: i.EKSCluster,
EKSRoleARN: i.EKSRoleARN,
Namespace: cfg.Namespace, Namespace: cfg.Namespace,
} }

View File

@@ -133,6 +133,33 @@ func (suite *InitKubeTestSuite) TestPrepareRequiredConfig() {
suite.Error(init.Prepare(cfg), "Token should be required.") suite.Error(init.Prepare(cfg), "Token should be required.")
} }
func (suite *InitKubeTestSuite) TestPrepareEKSConfig() {
templateFile, err := tempfile("kubeconfig********.yml.tpl", "hurgity burgity")
defer os.Remove(templateFile.Name())
suite.Require().Nil(err)
configFile, err := tempfile("kubeconfig********.yml", "")
defer os.Remove(configFile.Name())
suite.Require().Nil(err)
init := InitKube{
TemplateFile: templateFile.Name(),
ConfigFile: configFile.Name(),
APIServer: "eks.aws.amazonaws.com",
EKSCluster: "it-is-an-eks-parrot",
EKSRoleARN: "arn:aws:iam::19691207:role/mrPraline",
}
cfg := Config{}
suite.NoError(init.Prepare(cfg))
suite.Equal(init.values.EKSCluster, "it-is-an-eks-parrot")
suite.Equal(init.values.EKSRoleARN, "arn:aws:iam::19691207:role/mrPraline")
init.Token = "cGluaW5nIGZvciB0aGUgZmrDtnJkcw=="
suite.EqualError(init.Prepare(cfg), "token cannot be used simultaneously with eksCluster")
}
func (suite *InitKubeTestSuite) TestPrepareDefaultsServiceAccount() { func (suite *InitKubeTestSuite) TestPrepareDefaultsServiceAccount() {
templateFile, err := tempfile("kubeconfig********.yml.tpl", "hurgity burgity") templateFile, err := tempfile("kubeconfig********.yml.tpl", "hurgity burgity")
defer os.Remove(templateFile.Name()) defer os.Remove(templateFile.Name())

View File

@@ -78,6 +78,23 @@ func (suite *KubeconfigTestSuite) TestSetsSkipTLSVerify() {
suite.Contains(contents, "insecure-skip-tls-verify: true") suite.Contains(contents, "insecure-skip-tls-verify: true")
} }
func (suite *KubeconfigTestSuite) TestSetsEKSCluster() {
suite.initKube.Token = ""
suite.initKube.EKSCluster = "it-is-an-eks-parrot"
contents := suite.generateKubeconfig(Config{})
suite.Contains(contents, "command: aws-iam-authenticator")
suite.Contains(contents, `- "it-is-an-eks-parrot"`)
}
func (suite *KubeconfigTestSuite) TestSetsEKSRoleARN() {
suite.initKube.Token = ""
suite.initKube.EKSCluster = "it-is-an-eks-parrot"
suite.initKube.EKSRoleARN = "arn:aws:iam::19691207:role/mrPraline"
contents := suite.generateKubeconfig(Config{})
suite.Contains(contents, `- "-r"`)
suite.Contains(contents, `- "arn:aws:iam::19691207:role/mrPraline"`)
}
func (suite *KubeconfigTestSuite) generateKubeconfig(cfg Config) string { func (suite *KubeconfigTestSuite) generateKubeconfig(cfg Config) string {
suite.Require().NoError(suite.initKube.Prepare(cfg)) suite.Require().NoError(suite.initKube.Prepare(cfg))
suite.Require().NoError(suite.initKube.Execute(cfg)) suite.Require().NoError(suite.initKube.Execute(cfg))