Skip to content
This repository has been archived by the owner on Jun 15, 2021. It is now read-only.

Commit

Permalink
refactoring kube-aws / experimental IAM-based kubelet auth (kubernete…
Browse files Browse the repository at this point in the history
…s-retired#1490)

* update vendor

* refactoring kube-aws / experimental IAM-based kubelet auth

This is the successor of kubernetes-retired#1473. I'll keep that one for recording purposes.

Resolves kubernetes-retired#1469

 ## What do we get from this?

- Better, documented kube-aws plugin system. Use builtin plugins or write your own with a single file called `plugin.yaml`, to customize every aspect of kube-aws clusters.
- aws-iam-authenticator for kubelet auth, as a kube-aws plugin
- (near future) EKS support kubernetes-retired#1434 powered by the plugin system

 ## Story

Take this as a continuation of kubernetes-retired#509 (comment)

Towards the EKS integration(kubernetes-retired#1434), I have been working on the support for aws-iam-authenticator for kubelet authentication. And I was very annoyed by that I was forced to add small snippets of bash, cloud-config and go into several diverse locations of kube-aws's code-base, plus adding the feature to somehow obtain and transfer the `aws-iam-authenticator` "binary" onto kube-aws worker and controller nodes.

To summarize, things that I had to consider were:

- Creating a single keypair whose cert has two purposes - CA and Server Authn, encrypting it inside the `credentials/` dir, transferring to worker and controller nodes
- Somehow downloading and installing `aws-iam-authenticator` binary onto nodes
- Installing the aws-iam-authenticator deployment onto the k8s cluster
- Creating a configmap for aws-iam-authenticator that refers to IAM roles that are managed by kube-aws(Templating the configmap with the results of cloudformation functions? I'm tired of writing a long `{{ "Fn::Join": ["", ["long", "bash", "script", "separated and enclosed within double-quotes", "per", "line"]]}}` thing.

Being pretty annoyed, recalling kubernetes-retired#751 kubernetes-retired#791  kubernetes-retired#509, I decided to enhance the secret feature of kube-aws - "plugins" - to cover the use-case. It is resulting in a major refactoring of kube-aws.

It doesn't affect existing features of kube-aws at all. But it does affect public members exposed by several kube-aws go packages, and how golang packages are organized.

So to whom using kube-aws a golang library, this refactoring may affect you. Please feel free to send any feedback on that.

 # Notables user-visible changes

 ## Improved plugin system

Create a `plugin.yaml` at `PROJECT_ROOT/plugins/NAME/plugin.yaml` and edit according to your needs. [The aws-iam-authenticator plugin](https://github.com/mumoshu/kube-aws/blob/aws-iam-node-auth/builtin/files/plugins/aws-iam-authenticator/plugin.yaml) would be the most informative source for learning how it write it.

It can be used for:

 ### Existing features

- Installing Kubernetes manifests
- Installing files selected from the `plugins/NAME` directory onto nodes
- Injecting custom CloudFormation resources into kube-aws managed stacks

 ### New features

 #### Automatically turning yaml templates to cfn expressions

Imagine you have a YAML template file that looks like the below in your plugin's directory:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapRoles: |
{{ range $i, $role := .Config.IAMRoleARNs }},
  - rolearn: {{$role}}
    username: system:node:{{`{{EC2PrivateDNSName}}`}}
    groups:
    - system:bootstrappers
    - system:nodes
{{ end }}
```

Firstly this is rendered with golang's text/template:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapRoles: |
  - rolearn: {"Fn::GetAtt": ["IAMRoleController", "Arn"]}
    username: system:node:{{`{{EC2PrivateDNSName}}`}}
    groups:
    - system:bootstrappers
    - system:nodes
```

And this is where kube-was becomes fancy. It detects `{"Fn::GetAtt": ["IAMRoleController", "Arn"]}` that looks like a CFN stack template expression, and converts it to:

```json
{ "Fn::Join": ["", [
"apiVersion: v1\n",
"kind: ConfigMap\n",
"metadata:\n",
"  name: aws-auth\n",
"  namespace: kube-system\n",
"data:\n",
"  mapRoles: |\n",
"  - rolearn: ", {"Fn::GetAtt": ["IAMRoleController", "Arn"]}, "\n",
"    username: system:node:{{`{{EC2PrivateDNSName}}`}}\n",
"    groups:\n",
"    - system:bootstrappers\n",
"    - system:nodes\n",
]]}
```

This is then injected into the `AWS::CloudFormation::Init` so that `cfn-init` can rendered the file with the `{"Fn::GetAtt": ["IAMRoleController", "Arn"]}` replaced with the actual ARN of the IAM role managed by kube-aws.

```json
"Metadata" : {
  "AWS::CloudFormation::Init" : {
    "configSets: {
      "path-to-file": {
        "files": {
          "/path/to/file": { "Fn::Join": ["", [
            "apiVersion: v1\n",
            "kind: ConfigMap\n",
            "metadata:\n",
            "  name: aws-auth\n",
            "  namespace: kube-system\n",
            "data:\n",
            "  mapRoles: |\n",
            "  - rolearn: ", {"Fn::GetAtt": ["IAMRoleController", "Arn"]}, "\n",
            "    username: system:node:{{`{{EC2PrivateDNSName}}`}}\n",
            "    groups:\n",
            "    - system:bootstrappers\n",
            "    - system:nodes\n",
            ]]}
        }
    }
  }
}
```

 #### Automatically downloading files from source URLS

```yaml
spec:
  cluster:
    machine:
      roles:
        controller:
          files:
          - path: "/opt/bin/heptio-authenticator-aws"
            permissions: 0755
            type: binary
            source:
              path: "files/aws-iam-auth/opt/bin/heptio-authenticator-aws"
              url: "https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v0.3.0/heptio-authenticator-aws_0.3.0_linux_amd64"
```

 #### Defining additional keypairs used by k8s apps that the plugin supports:

```yaml
spec:
  cluster:
    pki:
      keypairs:
      - name: aws-iam-authenticator
        dnsNames:
        - localhost
        ipAddresses:
        - 0.0.0.0
        - 127.0.0.1
        duration: 8760h
        usages:
        - ca
        - server
```

For example, the above plugin.yaml results in `kube-aws render credential` creatning `plugins/aws-iam-authenticator/credentials/aws-iam-authenticator{-key,}.pem` files, that are then installed on nodes for use by the aws-iam-authenticator pods.

 ## `kube-aws render stack`

It now renders a set of files under the `plugins/aws-iam-authenticator` diretory:

- `plugin.yaml`
- `manifests/*.yaml` for the daemonset and the configmap
- `files/*.yaml` for kubeconfig files for the webhook authentication and kubelets

 ## `kube-aws render stack`

It now renders a set of credentials(keypairs) as defined in `plugins/NAME/plugin.yaml` files.

 # Notable internal changes

 ## Single place to store embedded files

kube-aws after this work will have a single place to store files embedded into kube-aws binaries. Here's how it looks https://github.com/mumoshu/kube-aws/tree/aws-iam-node-auth/builtin/files.

```
$ tree builtin/files
builtin/files
├── cluster.yaml.tmpl
├── credentials
├── etcdadm
│   ├── Makefile
│   ├── README.md
│   ├── etcdadm
│   └── test
├── kubeconfig.tmpl
├── manifests
├── plugins
│   └── aws-iam-authenticator
│       ├── files
│       │   ├── authentication-token-webhook-config.yaml
│       │   ├── controller-kubeconfig.yaml
│       │   └── worker-kubeconfig.yaml
│       ├── manifests
│       │   ├── aws-auth-cm.yaml
│       │   └── daemonset.yaml
│       └── plugin.yaml
├── stack-templates
│   ├── control-plane.json.tmpl
│   ├── etcd.json.tmpl
│   ├── network.json.tmpl
│   ├── node-pool.json.tmpl
│   └── root.json.tmpl
└── userdata
    ├── cloud-config-controller
    ├── cloud-config-etcd
    └── cloud-config-worker

9 directories, 20 files
```

 # Changelog since 1473

The changes between this and kubernetes-retired#1473 are as follows - just reviving accidentally removed files:

```
$ git diff aws-iam-node-auth
diff --git a/.gitignore b/.gitignore
index 62e8dc26..b33d23d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,8 @@ kube-aws
 coverage.txt
 profile.out
 test-result.json
+pkg/model/cache
+builtin/a_builtin-packr.go

 # gitbook docs
 _book
diff --git a/hack/relnote b/hack/relnote
new file mode 100755
index 00000000..f01e9fd6
--- /dev/null
+++ b/hack/relnote
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+go get golang.org/x/oauth2
+go get golang.org/x/net/context
+go get github.com/google/go-github/github
+
+VERSION=$(hack/version) go run hack/relnote.go
diff --git a/hack/version b/hack/version
new file mode 100755
index 00000000..0f4c6780
--- /dev/null
+++ b/hack/version
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+COMMIT=$(git rev-parse HEAD)
+TAG=$(git describe --exact-match --abbrev=0 --tags "${COMMIT}" 2> /dev/null || true)
+
+echo "${TAG}"
diff --git a/kube-aws-bot-git-ssh-key.enc b/kube-aws-bot-git-ssh-key.enc
new file mode 100644
index 00000000..fef826ba
```
  • Loading branch information
mumoshu authored and Kevin Taylor committed Jan 9, 2019
1 parent 36ec835 commit 435cbb7
Show file tree
Hide file tree
Showing 2,407 changed files with 27,960 additions and 1,476,317 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ kube-aws
.envrc
coverage.txt
profile.out
test-result.json
pkg/model/cache
builtin/a_builtin-packr.go

# gitbook docs
_book
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ go:
- 1.11.x
go_import_path: github.com/kubernetes-incubator/kube-aws
script:
- make test-with-cover
- travis_wait 40 make test-with-cover
after_success:
- bash <(curl -s https://codecov.io/bash)
deploy:
Expand Down
145 changes: 25 additions & 120 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,11 @@ ignored = ["github.com/kubernetes-incubator/kube-aws/hack*"]
[[constraint]]
version = "v1.2.0"
name = "github.com/aws/amazon-vpc-cni-k8s"

[[constraint]]
name = "github.com/google/go-cmp"
version = "0.2.0"

[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,12 @@ publish-docs: generate-docs

.PHONY: relnote
relnote:
@hack/relnote
go get golang.org/x/oauth2
go get golang.org/x/net/context
go get github.com/google/go-github/github
go run hack/relnote.go

.PHONY: merged-branches
merged-branches:
@git branch --merged | egrep -v "(^\*|master|v0.)"
@bash -c "(echo 'pipe this into \`| xargs git branch -d\`' to delete) 1>&2"
2 changes: 0 additions & 2 deletions OWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
reviewers:
- c-knowles
- danielfm
- davidmccormick
- mumoshu
- redbaron
approvers:
- c-knowles
- danielfm
- davidmccormick
- mumoshu
- redbaron
4 changes: 2 additions & 2 deletions awsconn/awsconn.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/kubernetes-incubator/kube-aws/model"
"github.com/kubernetes-incubator/kube-aws/pkg/api"
)

// NewSessionFromRegion creaes an AWS session from AWS region and a debug flag
func NewSessionFromRegion(region model.Region, debug bool) (*session.Session, error) {
func NewSessionFromRegion(region api.Region, debug bool) (*session.Session, error) {
awsConfig := aws.NewConfig().
WithRegion(region.String()).
WithCredentialsChainVerboseErrors(true)
Expand Down
40 changes: 13 additions & 27 deletions build
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,24 @@ fi

echo Building kube-aws ${VERSION}

# generate controlplane templates
pushd core/controlplane/config
go run ../../../codegen/templates_gen.go CloudConfigController=cloud-config-controller KubeConfigTemplate=kubeconfig.tmpl StackTemplateTemplate=stack-template.json
gofmt -w templates.go
go run ../../../codegen/files_gen.go Etcdadm=../../../etcdadm/etcdadm
gofmt -w files.go
popd

pushd core/network/config
go run ../../../codegen/templates_gen.go StackTemplateTemplate=stack-template.json
gofmt -w templates.go
popd

pushd core/etcd/config
go run ../../../codegen/templates_gen.go StackTemplateTemplate=stack-template.json CloudConfigEtcd=cloud-config-etcd
gofmt -w templates.go
popd

pushd core/nodepool/config
go run ../../../codegen/templates_gen.go StackTemplateTemplate=stack-template.json CloudConfigWorker=cloud-config-worker
gofmt -w templates.go
popd
printf 'Checking existence of the `packr` command that is used for embedding files into the resulting binary...'
if ! which packr 1>/dev/null; then
echo not found. installing...
go get -u github.com/gobuffalo/packr/packr
echo 'Installed `packr`.'
printf 'Ensuring that the installed command is available via PATH...'
export PATH=$PATH:$GOPATH/bin
echo 'done. PATH is now '"$PATH"
else
echo found. Skipped installation.
fi

pushd core/root/config
go run ../../../codegen/templates_gen.go StackTemplateTemplate=stack-template.json DefaultClusterConfig=cluster.yaml
gofmt -w templates.go
popd
packr -vz

if [[ ! "${BUILD_GOOS:-}" == "" ]];then
export GOOS=$BUILD_GOOS
fi
if [[ ! "${BUILD_GOARCH:-}" == "" ]];then
export GOARCH=$BUILD_GOARCH
fi
go build -ldflags "-X github.com/kubernetes-incubator/kube-aws/core/controlplane/cluster.VERSION=${VERSION}" -a -tags netgo -installsuffix netgo -o "$OUTPUT_PATH" ./
go build -ldflags "-X github.com/kubernetes-incubator/kube-aws/pkg/model.VERSION=${VERSION}" -a -tags netgo -installsuffix netgo -o "$OUTPUT_PATH" ./
Loading

0 comments on commit 435cbb7

Please sign in to comment.