github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/build/cluster/secret.go (about)

     1  /*
     2  Copyright 2019 The Skaffold Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package cluster
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  	"io/ioutil"
    24  
    25  	v1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	typedV1 "k8s.io/client-go/kubernetes/typed/core/v1"
    28  
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/kaniko"
    30  	kubernetesclient "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/client"
    31  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
    32  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
    33  )
    34  
    35  const (
    36  	defaultKanikoSecretPath = "kaniko-secret"
    37  )
    38  
    39  func (b *Builder) setupPullSecret(ctx context.Context, out io.Writer) (func(), error) {
    40  	if b.PullSecretPath == "" && b.PullSecretName == "" {
    41  		return func() {}, nil
    42  	}
    43  
    44  	output.Default.Fprintf(out, "Checking for kaniko secret [%s/%s]...\n", b.Namespace, b.PullSecretName)
    45  	client, err := kubernetesclient.DefaultClient()
    46  	if err != nil {
    47  		return nil, fmt.Errorf("getting Kubernetes client: %w", err)
    48  	}
    49  
    50  	secrets := client.CoreV1().Secrets(b.Namespace)
    51  	if _, err := secrets.Get(ctx, b.PullSecretName, metav1.GetOptions{}); err != nil {
    52  		output.Default.Fprintf(out, "Creating kaniko secret [%s/%s]...\n", b.Namespace, b.PullSecretName)
    53  		if b.PullSecretPath == "" {
    54  			return nil, fmt.Errorf("secret %s does not exist. No path specified to create it", b.PullSecretName)
    55  		}
    56  		return b.createSecretFromFile(ctx, secrets)
    57  	}
    58  	if b.PullSecretPath == "" {
    59  		// TODO: Remove the warning when pod health check can display pod failure errors.
    60  		log.Entry(ctx).Warnf("Assuming the secret %s is mounted inside Kaniko pod with the filename %s. If your secret is mounted at different path, please specify using config key `pullSecretPath`.\nSee https://skaffold.dev/docs/references/yaml/#build-cluster-pullSecretPath", b.PullSecretName, defaultKanikoSecretPath)
    61  		b.PullSecretPath = defaultKanikoSecretPath
    62  		return func() {}, nil
    63  	}
    64  	return func() {}, nil
    65  }
    66  
    67  func (b *Builder) createSecretFromFile(ctx context.Context, secrets typedV1.SecretInterface) (func(), error) {
    68  	secretData, err := ioutil.ReadFile(b.PullSecretPath)
    69  	if err != nil {
    70  		return nil, fmt.Errorf("cannot create secret %s from path %s. reading pull secret: %w", b.PullSecretName, b.PullSecretPath, err)
    71  	}
    72  	secret := &v1.Secret{
    73  		ObjectMeta: metav1.ObjectMeta{
    74  			Name:   b.PullSecretName,
    75  			Labels: map[string]string{"skaffold-kaniko": "skaffold-kaniko"},
    76  		},
    77  		Data: map[string][]byte{
    78  			kaniko.DefaultSecretName: secretData,
    79  		},
    80  	}
    81  	b.PullSecretPath = kaniko.DefaultSecretName
    82  	if _, err := secrets.Create(ctx, secret, metav1.CreateOptions{}); err != nil {
    83  		return nil, fmt.Errorf("creating pull secret %q: %w", b.PullSecretName, err)
    84  	}
    85  
    86  	return func() {
    87  		if err := secrets.Delete(ctx, b.PullSecretName, metav1.DeleteOptions{}); err != nil {
    88  			log.Entry(ctx).Warn("deleting pull secret")
    89  		}
    90  	}, nil
    91  }
    92  
    93  func (b *Builder) setupDockerConfigSecret(ctx context.Context, out io.Writer) (func(), error) {
    94  	if b.DockerConfig == nil {
    95  		return func() {}, nil
    96  	}
    97  
    98  	output.Default.Fprintf(out, "Creating docker config secret [%s]...\n", b.DockerConfig.SecretName)
    99  
   100  	client, err := kubernetesclient.DefaultClient()
   101  	if err != nil {
   102  		return nil, fmt.Errorf("getting Kubernetes client: %w", err)
   103  	}
   104  
   105  	secrets := client.CoreV1().Secrets(b.Namespace)
   106  
   107  	if b.DockerConfig.Path == "" {
   108  		log.Entry(ctx).Debug("No docker config specified. Checking for one in the cluster.")
   109  
   110  		if _, err := secrets.Get(ctx, b.DockerConfig.SecretName, metav1.GetOptions{}); err != nil {
   111  			return nil, fmt.Errorf("checking for existing kaniko secret: %w", err)
   112  		}
   113  
   114  		return func() {}, nil
   115  	}
   116  
   117  	secretData, err := ioutil.ReadFile(b.DockerConfig.Path)
   118  	if err != nil {
   119  		return nil, fmt.Errorf("reading docker config: %w", err)
   120  	}
   121  
   122  	secret := &v1.Secret{
   123  		ObjectMeta: metav1.ObjectMeta{
   124  			Name:   b.DockerConfig.SecretName,
   125  			Labels: map[string]string{"skaffold-kaniko": "skaffold-kaniko"},
   126  		},
   127  		Data: map[string][]byte{
   128  			"config.json": secretData,
   129  		},
   130  	}
   131  
   132  	if _, err := secrets.Create(ctx, secret, metav1.CreateOptions{}); err != nil {
   133  		return nil, fmt.Errorf("creating docker config secret %q: %w", b.DockerConfig.SecretName, err)
   134  	}
   135  
   136  	return func() {
   137  		if err := secrets.Delete(ctx, b.DockerConfig.SecretName, metav1.DeleteOptions{}); err != nil {
   138  			log.Entry(ctx).Warn("deleting docker config secret")
   139  		}
   140  	}, nil
   141  }