-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding Credential Provider Package with source and helm chart #829
Conversation
Skipping CI for Draft Pull Request. |
/hold |
/unhold |
@@ -0,0 +1,24 @@ | |||
apiVersion: skaffold/v3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure we want this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This combined with the dockerfile helps enable locally testing. This package is otherwise hard to test locally as its meant to run on the node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For vscode users maybe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never used skaffold. Might be worth doing a quick demo to see if it's a tool we might leverage.
ARG SKAFFOLD_GO_GCFLAGS | ||
RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -o app cmd/aws-credential-provider/*.go | ||
|
||
CMD ["/app/app"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I never like that we have docker files, but don't use them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case the dockerfile is useful for local testing as this binary can't really be tested locally since it requires the dependent binaries (ecr-credential-provider, iam-signing-helper) to copy.
credentialproviderpackage/Makefile
Outdated
|
||
build-linux: | ||
[ -d bin ] || mkdir bin | ||
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(MAKE) build |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we need to build this for linux arm and amd?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't think we supported ARM for the actual cluster but I can add it. Should work the same on ARM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're not going to use this makefile for the actual image build right? This will be in build-tooling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The package controller does do arch or os builds
build: go.sum generate ## Build package-manager binary.
$(GO) build -o $(BIN_DIR)/package-manager main.go
checkErrAndLog(err, utils.ErrorLogger) | ||
|
||
utils.InfoLogger.Println("Kubelet Restarted") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could increase your test coverage a lot if this was broken up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How so?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code isn't tested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you would like to see a test where the configurator interface is mocked this code is called from another package?
config constants.CredentialProviderConfigOptions | ||
} | ||
|
||
type AwsCred struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type AwsCred struct { | |
type awsCred struct { |
Maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use this at all since it only contains one instance of Aws
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used to match the bottlerocket api. I just generated the stucts based on the json.
credentialproviderpackage/Dockerfile
Outdated
@@ -0,0 +1,14 @@ | |||
FROM golang:1.18-buster |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to use internal base images here. But why do we need a Dockerfile here, this will be in build-tooling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So both this dockerfile and makefile are used for local testing. I am fine to remove it
@@ -0,0 +1,24 @@ | |||
apiVersion: v2 | |||
name: credential-provider-package | |||
description: A Helm chart for Kubernetes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clean up this file.
@@ -0,0 +1 @@ | |||
1. Installed Credential Provider Package |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you remove this file?
{{- end}} | ||
env: | ||
- name: OS_TYPE | ||
value: {{ template "template.getOSName" }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reuse $os
credentialproviderpackage/Makefile
Outdated
|
||
build-linux: | ||
[ -d bin ] || mkdir bin | ||
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(MAKE) build |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're not going to use this makefile for the actual image build right? This will be in build-tooling.
credentialproviderpackage/charts/credential-provider-package/templates/daemonset.yaml
Show resolved
Hide resolved
credentialproviderpackage/charts/credential-provider-package/templates/serviceaccount.yaml
Show resolved
Hide resolved
{{- end}} | ||
env: | ||
- name: OS_TYPE | ||
value: {{ template "template.getOSName" }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reuse $os
} | ||
|
||
func main() { | ||
utils.InfoLogger.Println("Running at " + time.Now().UTC().String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't print the date. Logs are already dated.
var configurator cfg.Configurator | ||
osType := strings.ToLower(os.Getenv("OS_TYPE")) | ||
if osType == "" { | ||
utils.ErrorLogger.Println("Missing Environment Variable OS") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utils.ErrorLogger.Println("Missing Environment Variable OS") | |
utils.ErrorLogger.Println("Missing Environment Variable OS_TYPE") |
) | ||
|
||
func init() { | ||
InfoLogger = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't include the date. Agree with Terry on this package.
|
||
func checkErrAndLog(err error, logger *log.Logger) { | ||
if err != nil { | ||
logger.Println(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're always doing os.EXIT(1), don't take a logger as input and call log.Fatal
. Although repeatedly checking errors with if err != nil { ... }
is annoying, this function call doesn't really improve it much if at all. I'd instead do the check directly and remove this.
configurator = bottlerocket.NewBottleRocketConfigurator(constants.SocketPath) | ||
|
||
} else { | ||
utils.ErrorLogger.Printf("Unexpected type %s expected socket\n", socket.Mode().Type()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just call log.Fatal
credentialproviderpackage/go.mod
Outdated
@@ -0,0 +1,28 @@ | |||
module credential-provider | |||
|
|||
go 1.18 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use 1.19
config constants.CredentialProviderConfigOptions | ||
} | ||
|
||
type AwsCred struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use this at all since it only contains one instance of Aws
?
type credentialProviders struct { | ||
EcrCredentialProvider ecrCredentialProvider `json:"ecr-credential-provider"` | ||
} | ||
type kubernetes struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see many structs that contain a single thing of another type. Why do we need those?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These structs were from br where they can have more in the structure, however I removed the used portions from ours.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think they are messages to BR
}, | ||
patchResponse: response{ | ||
statusCode: http.StatusNoContent, | ||
expectedBody: []byte("{\"aws\":{\"config\":\"W3Byb2ZpbGUgZWtzYS1wYWNrYWdlc10KYXdzX2FjY2Vzc19rZXlfaWQ9QUtJQUlPU0ZPRE5ON0VYQU1QTEUKYXdzX3NlY3JldF9hY2Nlc3Nfa2V5PXdKYWxyWFV0bkZFTUkvSzdNREVORy9iUHhSZmlDWUVYQU1QTEVLRVk=\",\"profile\":\"eksa-packages\",\"region\":\"\"}}"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider decoding this and calling the encode function before creating this object.
credentialproviderpackage/Makefile
Outdated
|
||
build-linux: | ||
[ -d bin ] || mkdir bin | ||
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(MAKE) build |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The package controller does do arch or os builds
build: go.sum generate ## Build package-manager binary.
$(GO) build -o $(BIN_DIR)/package-manager main.go
apiVersion: credentialprovider.kubelet.k8s.io/v1alpha1 | ||
env: | ||
- name: AWS_PROFILE | ||
value: eksa-packages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value: eksa-packages | |
value: {{.profile}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the test file that is matched against hence the values being written here instead of templating.
apiVersion: credentialprovider.kubelet.k8s.io/v1alpha1 | ||
env: | ||
- name: AWS_PROFILE | ||
value: eksa-packages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value: eksa-packages | |
value: {{.profile}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, This is the test file that is matched against hence the values being written here instead of templating.
application: | ||
secretName: aws-cred | ||
matchImages: [] | ||
defaultCacheDuration: "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should the chart provide a default duration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can include one, currently the application provides one if not included by chart
if osType == "" { | ||
log.ErrorLogger.Println("Missing Environment Variable OS_TYPE") | ||
os.Exit(1) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine, why not command line args?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I usually just fine environment variables easier to test with and setup IDEs as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Command line args are better I think in this case. One can easily find the args that need to be used without needing to run the application vs in this case the application needs to be run to find out what is missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find command line args are more difficult to test with tools such as scaffold where they try to override the entrypoint with a different one for debugging.
If there is strong feelings towards this let me know and I can change it to command line
} | ||
|
||
out := strings.Join(lines, "\n") | ||
err = ioutil.WriteFile(c.extraArgsPath, []byte(out), 0644) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
World read?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is the KUBELET_EXTRA_ARGS file which by default is world read
func copyBinaries() (string, error) { | ||
srcPath := constants.BinPath + constants.ECRCredProviderBinary | ||
dstPath := constants.BasePath + constants.ECRCredProviderBinary | ||
err := copyWithPermissons(srcPath, dstPath, 0744) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
World read? If these are binaries, why not 755?
|
||
srcPath = constants.BinPath + constants.IAMRolesSigningBinary | ||
dstPath = constants.BasePath + constants.IAMRolesSigningBinary | ||
err = copyWithPermissons(srcPath, dstPath, 0744) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
World read? Even group read I would question.
@@ -0,0 +1,41 @@ | |||
package constants | |||
|
|||
const ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why globals? Each thing should have their own constants and most likely all or at least some of these can be lower case for reduced scope
@@ -0,0 +1,24 @@ | |||
apiVersion: skaffold/v3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For vscode users maybe
wantFile := ReadFile(t, wantPath) | ||
|
||
if gotFile != wantFile { | ||
cmd := exec.Command("diff", wantPath, gotPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to diff? This adds a dependency to an OS binary which could be avoided by simply running a hash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is a small price to pay for easy test debugging. Do we need to support running on windows?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is diff in test directory so it will not be in needed in the final image
if err != nil { | ||
return err | ||
} | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are many instances of similar things across the PR. It doesn't affect functionality but the if is unnecessary.
if err != nil { | |
return err | |
} | |
return nil | |
return err |
key2: {{ .Key2 }} | ||
{{ if .Conditional }} | ||
{{ .KeyAndValue3 | indent 2 }} | ||
{{ end }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no newline at EOF
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This package and filewriter were copied from eks-anywhere. I would like to keep the consistency between the two
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Text files need to end with \n
under the unix spec. If this comes from the partialyaml.go trimsuffix, we should remove that or fix the logic.
) | ||
|
||
func init() { | ||
InfoLogger = log.New(os.Stdout, "INFO: ", log.Ltime|log.Lshortfile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the time.
credentialproviderpackage/Makefile
Outdated
|
||
REPO_ROOT=$(shell git rev-parse --show-toplevel)/credentialproviderpackage | ||
GOLANG_VERSION?="1.19" | ||
#GO ?= $(shell source $(REPO_ROOT)/scripts/common.sh && build::common::get_go_path $(GOLANG_VERSION))/go |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this if it is not used.
- name: aws-creds | ||
mountPath: /secrets/aws-creds | ||
{{ $os := include "template.getOSName" .}} | ||
{{- if eq $os "bottlerocket" }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should reduce the logic here. Maybe move it to the helpers.tpl?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as other comment
secret: | ||
secretName: {{.Values.application.secretName}} | ||
optional: false | ||
{{- if eq $os "bottlerocket" }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should reduce the logic here. Maybe move it to the helpers.tpl?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strongly prefer to keep this logic here. Makes the daemonset on its own much easier to read then having to figure out whats mounted from helpers.tpl
|
||
import ( | ||
_ "embed" | ||
"github.com/fsnotify/fsnotify" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we try to run a gofmt on this and see if this is formatted correctly.
configurator = linux.NewLinuxConfigurator() | ||
} | ||
|
||
configurator.Initialize(config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I second Terry on breaking this code down. And also I think the main file has much more code than usual. Maybe break this down into several easily readable files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you guys have an example for what you would like to see. Currently the main file calls 5 functions, a constructor for the configurator, initializer, credential creator, create config, and commit changes. That is basically all the application really handles so I am not sure of the value of making it a seperate file.
@@ -0,0 +1,3 @@ | |||
[profile eksa-packages] | |||
aws_access_key_id=AKIAIOSFODNN7EXAMPLE | |||
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a new line.
…nitialize interface to remove socketpath and add that to bottlerocket constructor, Removed Notes from chart, moved from Deployment to Daemonset
…r to Amazon Linux 2
5b8853c
to
a7e35d0
Compare
@@ -17,4 +17,4 @@ jobs: | |||
- name: Run Gosec Security Scanner | |||
uses: securego/gosec@master | |||
with: | |||
args: --exclude-dir=kubetest-plugins --exclude-dir generatebundlefile --exclude-dir ecrtokenrefresher ./... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we have this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is for the github workflows
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but why is gosec ignoring parts of our repo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created issue #870 to follow up on this
# Default values for credential-provider. | ||
# This is a YAML-formatted file. | ||
|
||
replicaCount: 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is most likely unused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: junshun, lewisdiamond, TerryHowe The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
*Issue #717
Description of changes:
Adding source code and helm chart for credential provider package. This package provides nodes with credentials access to private registries using Kubernetes Credential Provider. This inital commit will only support Elastic Container Registry.
This package will take a aws config secret on the cluster and handle creation of the KubeletCredentialProviderConfig, putting binaries on the individual nodes, and setting the flags on the kubelet using a Daemonset.
For Bottlerocket there specific API is used to trigger the changes necessary on each node. For other OS a directory is mounted on the node to put the necessary files for authentication.
Notes For Review
credentialproviderpackage/charts - includes the helm chart following the format of other helm charts for packages. There is also a helper function added to detect OS which is used to mount file paths depending on the OS.
credentialproviderpackage/pkg/filewriter
credentialproviderpackage/pkg/templater
These two were manually brought over from eks-anywhere as to not have to force a dependency on them.
credentialproviderpackage/skaffold.yaml
Used to help locally test and debug changes