Skip to content
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

Add kops create secret dockerconfig feature #3087

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/kops/create_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ var (
# Create an new ssh public key called admin.
kops create secret sshpublickey admin -i ~/.ssh/id_rsa.pub \
--name k8s-cluster.example.com --state s3://example.com

kops create secret dockerconfig -f ~/.docker/config.json \
--name k8s-cluster.example.com --state s3://example.com
`))

create_secret_short = i18n.T(`Create a secret.`)
Expand All @@ -48,6 +51,7 @@ func NewCmdCreateSecret(f *util.Factory, out io.Writer) *cobra.Command {

// create subcommands
cmd.AddCommand(NewCmdCreateSecretPublicKey(f, out))
cmd.AddCommand(NewCmdCreateSecretDockerConfig(f, out))

return cmd
}
124 changes: 124 additions & 0 deletions cmd/kops/create_secret_dockerconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"

"github.com/spf13/cobra"
"k8s.io/kops/cmd/kops/util"
"k8s.io/kops/pkg/apis/kops/registry"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/kubernetes/pkg/util/i18n"
)

var (
create_secret_dockerconfig_long = templates.LongDesc(i18n.T(`
Create a new docker config, and store it in the state store.
Used to configure docker on each master or node (ie. for auth)
Use update to modify it, this command will only create a new entry.`))

create_secret_dockerconfig_example = templates.Examples(i18n.T(`
# Create an new docker config.
kops create secret dockerconfig -f /path/to/docker/config.json \
--name k8s-cluster.example.com --state s3://example.com
`))

create_secret_dockerconfig_short = i18n.T(`Create a docker config.`)
)

type CreateSecretDockerConfigOptions struct {
ClusterName string
DockerConfigPath string
}

func NewCmdCreateSecretDockerConfig(f *util.Factory, out io.Writer) *cobra.Command {
options := &CreateSecretDockerConfigOptions{}

cmd := &cobra.Command{
Use: "dockerconfig",
Short: create_secret_dockerconfig_short,
Long: create_secret_dockerconfig_long,
Example: create_secret_dockerconfig_example,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 0 {
exitWithError(fmt.Errorf("syntax: -f <DockerConfigPath>"))
}

err := rootCommand.ProcessArgs(args[0:])
if err != nil {
exitWithError(err)
}

options.ClusterName = rootCommand.ClusterName()

err = RunCreateSecretDockerConfig(f, os.Stdout, options)
if err != nil {
exitWithError(err)
}
},
}

cmd.Flags().StringVarP(&options.DockerConfigPath, "", "f", "", "Path to docker config JSON file")

return cmd
}

func RunCreateSecretDockerConfig(f *util.Factory, out io.Writer, options *CreateSecretDockerConfigOptions) error {
if options.DockerConfigPath == "" {
return fmt.Errorf("docker config path is required (use -f)")
}
secret, err := fi.CreateSecret()
if err != nil {
return fmt.Errorf("error creating docker config secret: %v", err)
}

cluster, err := GetCluster(f, options.ClusterName)
if err != nil {
return err
}

secretStore, err := registry.SecretStore(cluster)
if err != nil {
return err
}

data, err := ioutil.ReadFile(options.DockerConfigPath)
if err != nil {
return fmt.Errorf("error reading docker config %v: %v", options.DockerConfigPath, err)
}

var parsedData map[string]interface{}
err = json.Unmarshal(data, &parsedData)
if err != nil {
return fmt.Errorf("Unable to parse JSON %v: %v", options.DockerConfigPath, err)
}

secret.Data = data

_, _, err = secretStore.GetOrCreateSecret("dockerconfig", secret)
if err != nil {
return fmt.Errorf("error adding docker config secret: %v", err)
}

return nil
}
4 changes: 4 additions & 0 deletions docs/cli/kops_create_secret.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Create a secret
# Create an new ssh public key called admin.
kops create secret sshpublickey admin -i ~/.ssh/id_rsa.pub \
--name k8s-cluster.example.com --state s3://example.com

kops create secret dockerconfig -f ~/.docker/config.json \
--name k8s-cluster.example.com --state s3://example.com
```

### Options inherited from parent commands
Expand All @@ -35,5 +38,6 @@ Create a secret

### SEE ALSO
* [kops create](kops_create.md) - Create a resource by command line, filename or stdin.
* [kops create secret dockerconfig](kops_create_secret_dockerconfig.md) - Create a docker config.
* [kops create secret sshpublickey](kops_create_secret_sshpublickey.md) - Create a ssh public key.

48 changes: 48 additions & 0 deletions docs/cli/kops_create_secret_dockerconfig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

<!--- This file is automatically generated by make gen-cli-docs; changes should be made in the go CLI command code (under cmd/kops) -->

## kops create secret dockerconfig

Create a docker config.

### Synopsis


Create a new docker config, and store it in the state store. Used to configure docker on each master or node (ie. for auth) Use update to modify it, this command will only create a new entry.

```
kops create secret dockerconfig
```

### Examples

```
# Create an new docker config.
kops create secret dockerconfig -f /path/to/docker/config.json \
--name k8s-cluster.example.com --state s3://example.com
```

### Options

```
-f, -- string Path to docker config JSON file
```

### Options inherited from parent commands

```
--alsologtostderr log to standard error as well as files
--config string config file (default is $HOME/.kops.yaml)
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files (default false)
--name string Name of cluster
--state string Location of state storage
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
-v, --v Level log level for V logs
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```

### SEE ALSO
* [kops create secret](kops_create_secret.md) - Create a secret.

9 changes: 9 additions & 0 deletions docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ To change the SSH public key on an existing cluster:
* `kops update cluster --yes` to reconfigure the auto-scaling groups
* `kops rolling-update cluster --name <clustername> --yes` to immediately roll all the machines so they have the new key (optional)

## Docker Configuration

If you are using a private registry such as quay.io, you may be familiar with the inconvenience of managing the `imagePullSecrets` for each namespace. It can also be a pain to use [Kops Hooks](cluster_spec.md#hooks) with private images. To configure docker on all nodes with access to one or more private registries:

* `kops create secret --name <clustername> dockerconfig -f ~/.docker/config.json`
* `kops rolling-update cluster --name <clustername> --yes` to immediately roll all the machines so they have the new key (optional)

This stores the [config.json](https://docs.docker.com/engine/reference/commandline/login/) in `/root/.docker/config.json` on all nodes (include masters) so that both Kubernetes and system containers may use registries defined in it.

## IAM roles

All Pods running on your cluster have access to underlying instance IAM role.
Expand Down
2 changes: 2 additions & 0 deletions nodeup/pkg/model/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ func (b *KubeletBuilder) buildSystemdEnvironmentFile(kubeletConfig *kops.Kubelet
}

sysconfig := "DAEMON_ARGS=\"" + flags + "\"\n"
// Makes kubelet read /root/.docker/config.json properly
sysconfig = sysconfig + "HOME=\"/root" + "\"\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Came across this with the ~/.aws directory as well - it is a pain...

Wondering if we should give kubelet etc their own directories, but if we do we can just change it when we need it. Thanks for fixing :-)


t := &nodetasks.File{
Path: "/etc/sysconfig/kubelet",
Expand Down
18 changes: 18 additions & 0 deletions nodeup/pkg/model/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ func (b *SecretBuilder) Build(c *fi.ModelBuilderContext) error {
c.AddTask(t)
}

if b.SecretStore != nil {
key := "dockerconfig"
dockercfg, _ := b.SecretStore.Secret(key)
if dockercfg != nil {
contents := string(dockercfg.Data)
t := &nodetasks.File{
Path: filepath.Join("root", ".docker", "config.json"),
Contents: fi.NewStringResource(contents),
Type: nodetasks.FileType_File,
Mode: s("0600"),
}
c.AddTask(t)
}
}

// if we are not a master we can stop here
if !b.IsMaster {
return nil
Expand Down Expand Up @@ -129,6 +144,9 @@ func (b *SecretBuilder) Build(c *fi.ModelBuilderContext) error {

var lines []string
for id, token := range allTokens {
if id == "dockerconfig" {
continue
}
lines = append(lines, token+","+id+","+id)
}
csv := strings.Join(lines, "\n")
Expand Down
1 change: 1 addition & 0 deletions nodeup/pkg/model/tests/kubelet/featuregates/tasks.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
contents: |
DAEMON_ARGS="--feature-gates=AllowExtTrafficLocalEndpoints=false,ExperimentalCriticalPodAnnotation=true --node-labels=kubernetes.io/role=node,node-role.kubernetes.io/node= --cni-bin-dir=/opt/cni/bin/ --cni-conf-dir=/etc/cni/net.d/ --network-plugin-dir=/opt/cni/bin/"
HOME="/root"
path: /etc/sysconfig/kubelet
type: file