Skip to content

Commit

Permalink
Improvement in the kubeconfigwriter
Browse files Browse the repository at this point in the history
Kubeconfigwriter needs to improved to replace pipeline resource type "cluster" with thekubeconfig-creatortask.
In order to do that, some extra configurations (e.g. client-key-data, client-certificate-data) needs to be added with some changes in the implementation.

Signed-off-by: Divyansh42 <[email protected]>
  • Loading branch information
divyansh42 committed Apr 13, 2020
1 parent fea54e5 commit 1cdc6fa
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 23 deletions.
29 changes: 22 additions & 7 deletions cmd/kubeconfigwriter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ import (
)

var (
clusterConfig = flag.String("clusterConfig", "", "json string with the configuration of a cluster based on values from a cluster resource. Only required for external clusters.")
clusterConfig = flag.String("clusterConfig", "", "json string with the configuration of a cluster based on values from a cluster resource. Only required for external clusters.")
destinationDir = flag.String("destinationDir", "", "destination directory where generated kubeconfig file will be stored.")
)

func main() {
Expand All @@ -48,10 +49,10 @@ func main() {
if err != nil {
logger.Fatalf("Error reading cluster config: %v", err)
}
createKubeconfigFile(&cr, logger)
createKubeconfigFile(&cr, logger, destinationDir)
}

func createKubeconfigFile(resource *cluster.Resource, logger *zap.SugaredLogger) {
func createKubeconfigFile(resource *cluster.Resource, logger *zap.SugaredLogger, destinationDir *string) {
cluster := &clientcmdapi.Cluster{
Server: resource.URL,
InsecureSkipTLSVerify: resource.Insecure,
Expand All @@ -72,14 +73,18 @@ func createKubeconfigFile(resource *cluster.Resource, logger *zap.SugaredLogger)
//only one authentication technique per user is allowed in a kubeconfig, so clear out the password if a token is provided
user := resource.Username
pass := resource.Password
clientKeyData := resource.ClientKeyData
clientCertificateData := resource.ClientCertificateData
if resource.Token != "" {
user = ""
pass = ""
}
auth := &clientcmdapi.AuthInfo{
Token: resource.Token,
Username: user,
Password: pass,
Token: resource.Token,
Username: user,
Password: pass,
ClientKeyData: clientKeyData,
ClientCertificateData: clientCertificateData,
}
context := &clientcmdapi.Context{
Cluster: resource.Name,
Expand All @@ -95,7 +100,17 @@ func createKubeconfigFile(resource *cluster.Resource, logger *zap.SugaredLogger)
c.APIVersion = "v1"
c.Kind = "Config"

destinationFile := fmt.Sprintf("/workspace/%s/kubeconfig", resource.Name)
// kubeconfig file location
var destinationFile string

// If the destination Directory is provided, kubeconfig will be written to the given directory.
// otherwise it will use default location i.e. "/workspace/<cluster-name>/
if *destinationDir != "" {
destinationFile = fmt.Sprintf("%s/kubeconfig", *destinationDir)
} else {
destinationFile = fmt.Sprintf("/workspace/%s/kubeconfig", resource.Name)
}

if err := clientcmd.WriteToFile(*c, destinationFile); err != nil {
logger.Fatalf("Error writing kubeconfig to file: %v", err)
}
Expand Down
7 changes: 7 additions & 0 deletions docs/resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -648,11 +648,18 @@ The Cluster resource has the following parameters:
certificate.
- `cadata` (required): holds PEM-encoded bytes (typically read from a root
certificates bundle).
- `clientKeyData`: contains PEM-encoded data from a client key file
for TLS
- `clientCertificateData`: contains PEM-encoded data from a client cert file for TLS


Note: Since only one authentication technique is allowed per user, either a
`token` or a `password` should be provided, if both are provided, the `password`
will be ignored.

`clientKeyData` and `clientCertificateData` are only required if `token` or
`password` is not provided for authentication to cluster.

The following example shows the syntax and structure of a `cluster` resource:

```yaml
Expand Down
2 changes: 2 additions & 0 deletions docs/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ Each variable is accessible via `resources.inputs.<resource name>.<variable name
| `token` | Bearer token. |
| `insecure` | Whether TLS connection to server should be verified: `"true"` or `"false"`. |
| `cadata` | Stringified PEM-encoded bytes typically read from a root certificates bundle. |
| `clientKeyData` | Stringified PEM-encoded bytes from a client key file for TLS. |
| `clientCertificateData` | Stringified PEM-encoded bytes from a client cert file for TLS. |

#### CloudEvent PipelineResource

Expand Down
36 changes: 26 additions & 10 deletions pkg/apis/resource/v1alpha1/cluster/cluster_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ type Resource struct {
// CAData holds PEM-encoded bytes (typically read from a root certificates bundle).
// CAData takes precedence over CAFile
CAData []byte `json:"cadata"`
// ClientKeyData contains PEM-encoded data from a client key file for TLS.
ClientKeyData []byte `json:"clientKeyData"`
// ClientCertificateData contains PEM-encoded data from a client cert file for TLS.
ClientCertificateData []byte `json:"clientCertificateData"`
//Secrets holds a struct to indicate a field name and corresponding secret name to populate it
Secrets []resource.SecretParam `json:"secrets"`

Expand Down Expand Up @@ -88,6 +92,16 @@ func NewResource(kubeconfigWriterImage string, r *resource.PipelineResource) (*R
sDec, _ := b64.StdEncoding.DecodeString(param.Value)
clusterResource.CAData = sDec
}
case strings.EqualFold(param.Name, "ClientKeyData"):
if param.Value != "" {
sDec, _ := b64.StdEncoding.DecodeString(param.Value)
clusterResource.ClientKeyData = sDec
}
case strings.EqualFold(param.Name, "ClientCertificateData"):
if param.Value != "" {
sDec, _ := b64.StdEncoding.DecodeString(param.Value)
clusterResource.ClientCertificateData = sDec
}
}
}
clusterResource.Secrets = r.Spec.SecretParams
Expand Down Expand Up @@ -123,16 +137,18 @@ func (s *Resource) GetURL() string {
// Replacements is used for template replacement on a ClusterResource inside of a Taskrun.
func (s *Resource) Replacements() map[string]string {
return map[string]string{
"name": s.Name,
"type": s.Type,
"url": s.URL,
"revision": s.Revision,
"username": s.Username,
"password": s.Password,
"namespace": s.Namespace,
"token": s.Token,
"insecure": strconv.FormatBool(s.Insecure),
"cadata": string(s.CAData),
"name": s.Name,
"type": s.Type,
"url": s.URL,
"revision": s.Revision,
"username": s.Username,
"password": s.Password,
"namespace": s.Namespace,
"token": s.Token,
"insecure": strconv.FormatBool(s.Insecure),
"cadata": string(s.CAData),
"clientKeyData": string(s.ClientKeyData),
"clientCertificateData": string(s.ClientCertificateData),
}
}

Expand Down
22 changes: 21 additions & 1 deletion pkg/apis/resource/v1alpha1/cluster/cluster_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ func TestNewClusterResource(t *testing.T) {
Password: "pass",
KubeconfigWriterImage: "override-with-kubeconfig-writer:latest",
},
}, {
desc: "resource with clientKeyData and clientCertificateData instead of token or password",
resource: tb.PipelineResource("test-cluster-resource", "default", tb.PipelineResourceSpec(
resourcev1alpha1.PipelineResourceTypeCluster,
tb.PipelineResourceSpecParam("url", "http://10.10.10.10"),
tb.PipelineResourceSpecParam("username", "user"),
tb.PipelineResourceSpecParam("cadata", "bXktY2x1c3Rlci1jZXJ0Cg"),
tb.PipelineResourceSpecParam("clientKeyData", "Y2xpZW50LWtleS1kYXRh"),
tb.PipelineResourceSpecParam("clientCertificateData", "Y2xpZW50LWNlcnRpZmljYXRlLWRhdGE="),
)),
want: &cluster.Resource{
Name: "test-cluster-resource",
Type: resourcev1alpha1.PipelineResourceTypeCluster,
URL: "http://10.10.10.10",
Username: "user",
CAData: []byte("my-cluster-cert"),
ClientKeyData: []byte("client-key-data"),
ClientCertificateData: []byte("client-certificate-data"),
KubeconfigWriterImage: "override-with-kubeconfig-writer:latest",
},
}, {
desc: "set insecure flag to true when there is no cert",
resource: tb.PipelineResource("test-cluster-resource", "foo", tb.PipelineResourceSpec(
Expand Down Expand Up @@ -155,7 +175,7 @@ func TestClusterResource_GetInputTaskModifier(t *testing.T) {
Name: "kubeconfig-9l9zj",
Image: "override-with-kubeconfig-writer:latest",
Command: []string{"/ko-app/kubeconfigwriter"},
Args: []string{"-clusterConfig", `{"name":"test-cluster-resource","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"","token":"","Insecure":false,"cadata":null,"secrets":[{"fieldName":"cadata","secretKey":"cadatakey","secretName":"secret1"}]}`},
Args: []string{"-clusterConfig", `{"name":"test-cluster-resource","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"","token":"","Insecure":false,"cadata":null,"clientKeyData":null,"clientCertificateData":null,"secrets":[{"fieldName":"cadata","secretKey":"cadatakey","secretName":"secret1"}]}`},
Env: []corev1.EnvVar{{
Name: "CADATA",
ValueFrom: &corev1.EnvVarSource{
Expand Down
12 changes: 10 additions & 2 deletions pkg/apis/resource/v1alpha1/pipelineresource_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (rs *PipelineResourceSpec) Validate(ctx context.Context) *apis.FieldError {
return apis.ErrMissingField("spec.type")
}
if rs.Type == PipelineResourceTypeCluster {
var authFound, cadataFound, isInsecure bool
var authFound, cadataFound, clientKeyDataFound, clientCertificateDataFound, isInsecure bool
for _, param := range rs.Params {
switch {
case strings.EqualFold(param.Name, "URL"):
Expand All @@ -54,6 +54,10 @@ func (rs *PipelineResourceSpec) Validate(ctx context.Context) *apis.FieldError {
case strings.EqualFold(param.Name, "CAData"):
authFound = true
cadataFound = true
case strings.EqualFold(param.Name, "ClientKeyData"):
clientKeyDataFound = true
case strings.EqualFold(param.Name, "ClientCertificateData"):
clientCertificateDataFound = true
case strings.EqualFold(param.Name, "Token"):
authFound = true
case strings.EqualFold(param.Name, "insecure"):
Expand All @@ -71,10 +75,14 @@ func (rs *PipelineResourceSpec) Validate(ctx context.Context) *apis.FieldError {
cadataFound = true
}
}
// if both clientKeyData and clientCertificateData found
if clientCertificateDataFound && clientKeyDataFound {
authFound = true
}

// One auth method must be supplied
if !(authFound) {
return apis.ErrMissingField("username or CAData or token param")
return apis.ErrMissingField("username or CAData or token param or clientKeyData or ClientCertificateData")
}
if !cadataFound && !isInsecure {
return apis.ErrMissingField("CAData param")
Expand Down
10 changes: 9 additions & 1 deletion pkg/apis/resource/v1alpha1/pipelineresource_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func TestResourceValidation_Invalid(t *testing.T) {
Name: "username", Value: "admin",
}, {
Name: "token", Value: "my-token",
}, {
Name: "clientKeyData", Value: "Y2xpZW50LWtleS1kYXRh",
}, {
Name: "clientCertificateData", Value: "Y2xpZW50LWNlcnRpZmljYXRlLWRhdGE=",
}},
},
},
Expand All @@ -63,7 +67,7 @@ func TestResourceValidation_Invalid(t *testing.T) {
}},
},
},
want: apis.ErrMissingField("username or CAData or token param"),
want: apis.ErrMissingField("username or CAData or token param or clientKeyData or ClientCertificateData"),
}, {
name: "cluster with missing cadata",
res: &v1alpha1.PipelineResource{
Expand Down Expand Up @@ -171,6 +175,10 @@ func TestClusterResourceValidation_Valid(t *testing.T) {
Name: "username", Value: "admin",
}, {
Name: "token", Value: "my-token",
}, {
Name: "clientKeyData", Value: "Y2xpZW50LWtleS1kYXRh",
}, {
Name: "clientCertificateData", Value: "Y2xpZW50LWNlcnRpZmljYXRlLWRhdGE=",
}},
},
},
Expand Down
12 changes: 10 additions & 2 deletions pkg/reconciler/taskrun/resources/input_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,14 @@ func setUp() {
Name: "CAdata",
// echo "my-ca-cert" | base64
Value: "bXktY2EtY2VydAo=",
}, {
Name: "clientKeyData",
// echo "my-ca-cert" | base64
Value: "Y2xpZW50LWtleS1kYXRh",
}, {
Name: "clientCertificateData",
// echo "my-ca-cert" | base64
Value: "Y2xpZW50LWNlcnRpZmljYXRlLWRhdGE=",
}},
},
}, {
Expand Down Expand Up @@ -834,7 +842,7 @@ gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-dir
Image: "override-with-kubeconfig-writer:latest",
Command: []string{"/ko-app/kubeconfigwriter"},
Args: []string{
"-clusterConfig", `{"name":"cluster3","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"namespace1","token":"","Insecure":false,"cadata":"bXktY2EtY2VydAo=","secrets":null}`,
"-clusterConfig", `{"name":"cluster3","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"namespace1","token":"","Insecure":false,"cadata":"bXktY2EtY2VydAo=","clientKeyData":"Y2xpZW50LWtleS1kYXRh","clientCertificateData":"Y2xpZW50LWNlcnRpZmljYXRlLWRhdGE=","secrets":null}`,
},
}}},
Resources: &v1beta1.TaskResources{
Expand Down Expand Up @@ -884,7 +892,7 @@ gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-dir
Image: "override-with-kubeconfig-writer:latest",
Command: []string{"/ko-app/kubeconfigwriter"},
Args: []string{
"-clusterConfig", `{"name":"cluster2","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"","token":"","Insecure":false,"cadata":null,"secrets":[{"fieldName":"cadata","secretKey":"cadatakey","secretName":"secret1"}]}`,
"-clusterConfig", `{"name":"cluster2","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"","token":"","Insecure":false,"cadata":null,"clientKeyData":null,"clientCertificateData":null,"secrets":[{"fieldName":"cadata","secretKey":"cadatakey","secretName":"secret1"}]}`,
},
Env: []corev1.EnvVar{{
ValueFrom: &corev1.EnvVarSource{
Expand Down

0 comments on commit 1cdc6fa

Please sign in to comment.