Skip to content

Commit

Permalink
Remove Secrets and ServiceAccounts pages
Browse files Browse the repository at this point in the history
Remove the Secrets and ServiceAccounts pages from the Dashboard UI,
along with the associated Create Secret / Patch ServiceAccount
functionality.

These pages provide incomplete functionality, have little to no
benefit versus using `kubectl` or other tools to manage `Secrets`,
and incur a significant overhead in terms of code maintenance since
they have to be handled differently (e.g. sanitisation of secrets
in backend).

Also remove the RBAC rules giving the Dashboard access to get/list/...
Secrets in all namespaces. This should make the Dashboard's default
permissions a lot more palatable for many users who were reluctant
to give it access to this sensitive information.
  • Loading branch information
AlanGreene authored and tekton-robot committed Feb 9, 2021
1 parent e2b5e4f commit 68a2682
Show file tree
Hide file tree
Showing 69 changed files with 43 additions and 6,872 deletions.
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ replace (

require (
github.com/emicklei/go-restful v2.12.0+incompatible
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/golang/protobuf v1.4.2 // indirect
github.com/gorilla/websocket v1.4.2
github.com/imdario/mergo v0.3.9 // indirect
github.com/kr/text v0.2.0 // indirect
Expand Down
26 changes: 1 addition & 25 deletions overlays/patches/read-write/clusterrole-tenant-patch.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2020 The Tekton Authors
# Copyright 2020-2021 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -13,30 +13,6 @@
# limitations under the License.

---
- op: add
path: /rules/-
value:
apiGroups:
- ''
resources:
- serviceaccounts
verbs:
- update
- patch
- op: add
path: /rules/-
value:
apiGroups:
- ''
resources:
- secrets
verbs:
- get
- list
- watch
- create
- update
- delete
- op: add
path: /rules/-
value:
Expand Down
27 changes: 1 addition & 26 deletions packages/utils/src/utils/router.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019-2020 The Tekton Authors
Copyright 2019-2021 The Tekton 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
Expand Down Expand Up @@ -135,31 +135,6 @@ export const paths = {
return '/:type/:name';
}
},
secrets: {
all() {
return '/secrets';
},
byName() {
return byNamespace({ path: '/secrets/:secretName' });
},
byNamespace() {
return byNamespace({ path: '/secrets' });
},
create() {
return '/secrets/create';
}
},
serviceAccounts: {
all() {
return '/serviceaccounts';
},
byName() {
return byNamespace({ path: '/serviceaccounts/:serviceAccountName' });
},
byNamespace() {
return byNamespace({ path: '/serviceaccounts' });
}
},
taskRuns: {
all() {
return '/taskruns';
Expand Down
54 changes: 1 addition & 53 deletions packages/utils/src/utils/router.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019-2020 The Tekton Authors
Copyright 2019-2021 The Tekton 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
Expand All @@ -20,8 +20,6 @@ const namespace = 'fake_namespace';
const pipelineName = 'fake_pipelineName';
const pipelineResourceName = 'fake_pipelineResourceName';
const pipelineRunName = 'fake_pipelineRunName';
const secretName = 'fake_secretName';
const serviceAccountName = 'fake_serviceAccountName';
const taskName = 'fake_taskName';
const taskRunName = 'fake_taskRunName';
const triggerBindingName = 'fake_triggerBindingName';
Expand Down Expand Up @@ -283,56 +281,6 @@ describe('rawCRD', () => {
});
});

describe('secrets', () => {
it('all', () => {
expect(urls.secrets.all()).toEqual(generatePath(paths.secrets.all()));
});

it('byName', () => {
expect(urls.secrets.byName({ namespace, secretName })).toEqual(
generatePath(paths.secrets.byName(), {
namespace,
secretName
})
);
});

it('byNamespace', () => {
expect(urls.secrets.byNamespace({ namespace })).toEqual(
generatePath(paths.secrets.byNamespace(), { namespace })
);
});
});

describe('serviceAccounts', () => {
it('all', () => {
expect(urls.serviceAccounts.all()).toEqual(
generatePath(paths.serviceAccounts.all())
);
});

it('byName', () => {
expect(
urls.serviceAccounts.byName({ namespace, serviceAccountName })
).toEqual(
generatePath(paths.serviceAccounts.byName(), {
namespace,
serviceAccountName
})
);
});

it('byNamespace', () => {
expect(urls.serviceAccounts.byNamespace({ namespace })).toEqual(
generatePath(paths.serviceAccounts.byNamespace(), { namespace })
);
});

it('create', () => {
expect(urls.secrets.create()).toEqual(generatePath(paths.secrets.create()));
});
});

describe('taskRuns', () => {
it('all', () => {
expect(urls.taskRuns.all()).toEqual(generatePath(paths.taskRuns.all()));
Expand Down
5 changes: 1 addition & 4 deletions pkg/broadcaster/broadcaster.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019-2020 The Tekton Authors
Copyright 2019-2021 The Tekton 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
Expand Down Expand Up @@ -53,9 +53,6 @@ const (
ServiceExtensionCreated MessageType = "ServiceExtensionCreated"
ServiceExtensionUpdated MessageType = "ServiceExtensionUpdated"
ServiceExtensionDeleted MessageType = "ServiceExtensionDeleted"
SecretCreated MessageType = "SecretCreated"
SecretDeleted MessageType = "SecretDeleted"
SecretUpdated MessageType = "SecretUpdated"
ServiceAccountCreated MessageType = "ServiceAccountCreated"
ServiceAccountDeleted MessageType = "ServiceAccountDeleted"
ServiceAccountUpdated MessageType = "ServiceAccountUpdated"
Expand Down
1 change: 0 additions & 1 deletion pkg/controllers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ func StartKubeControllers(clientset k8sclientset.Interface, resyncDur time.Durat
kubecontroller.NewExtensionController(tenantInformerFactory, handler)
}
if !readOnly {
kubecontroller.NewSecretController(tenantInformerFactory)
kubecontroller.NewServiceAccountController(tenantInformerFactory)
}

Expand Down
37 changes: 0 additions & 37 deletions pkg/controllers/kubernetes/secret.go

This file was deleted.

19 changes: 16 additions & 3 deletions pkg/controllers/utils/controller.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
/*
Copyright 2020-2021 The Tekton 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 utils

import (
Expand Down Expand Up @@ -28,10 +41,10 @@ func NewController(kind string, informer cache.SharedIndexInformer, onCreated, o
endpoints.ResourcesChannel <- data
},
UpdateFunc: func(oldObj, newObj interface{}) {
oldSecret, newSecret := oldObj.(metav1.Object), newObj.(metav1.Object)
oldResource, newResource := oldObj.(metav1.Object), newObj.(metav1.Object)
// If resourceVersion differs between old and new, an actual update event was observed
if oldSecret.GetResourceVersion() != newSecret.GetResourceVersion() {
logging.Log.Debugf("Controller detected %s '%s' updated", kind, oldSecret.GetName())
if oldResource.GetResourceVersion() != newResource.GetResourceVersion() {
logging.Log.Debugf("Controller detected %s '%s' updated", kind, oldResource.GetName())
data := broadcaster.SocketData{
MessageType: onUpdated,
Payload: filter(newObj, true),
Expand Down
50 changes: 0 additions & 50 deletions pkg/endpoints/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,11 @@ import (
"errors"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"

restful "github.com/emicklei/go-restful"
"github.com/tektoncd/dashboard/pkg/logging"
"github.com/tektoncd/dashboard/pkg/utils"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
)

// Properties : properties we want to be able to retrieve via REST
Expand All @@ -45,8 +40,6 @@ type Properties struct {
ExternalLogsURL string `json:"ExternalLogsURL"`
}

var secretsURIPattern *regexp.Regexp = regexp.MustCompile("/secrets[?/]")

// ProxyRequest does as the name suggests: proxies requests and logs what's going on
func (r Resource) ProxyRequest(request *restful.Request, response *restful.Response) {
parsedURL, err := url.Parse(request.Request.URL.String())
Expand All @@ -57,14 +50,6 @@ func (r Resource) ProxyRequest(request *restful.Request, response *restful.Respo

uri := request.PathParameter("subpath") + "?" + parsedURL.RawQuery

if secretsURIPattern.Match([]byte(uri)) {
forwardRequest := r.K8sClient.CoreV1().RESTClient().Verb(request.Request.Method).RequestURI(uri).Body(request.Request.Body)
forwardRequest.SetHeader("Content-Type", request.HeaderParameter("Content-Type"))
forwardResponse := forwardRequest.Do()
handleSecretsResponse(response, forwardResponse)
return
}

if statusCode, err := utils.Proxy(request.Request, response, r.Config.Host+"/"+uri, r.HttpClient); err != nil {
utils.RespondError(response, err, statusCode)
}
Expand Down Expand Up @@ -131,38 +116,3 @@ func handleRequestError(response *restful.Response, responseBody []byte, request
}
utils.RespondError(response, requestError, http.StatusInternalServerError)
}

func handleSecretsResponse(response *restful.Response, forwardResponse rest.Result) {
responseBody, requestError := forwardResponse.Get()
if requestError != nil {
responseBodyRaw, requestError := forwardResponse.Raw()
handleRequestError(response, responseBodyRaw, requestError)
return
}

var responseObject interface{}

list, _ := responseBody.(*corev1.SecretList)
if list != nil {
logging.Log.Debug("Processing SecretList response")
secrets := make([]corev1.Secret, 0, len(list.Items))
for _, secret := range list.Items {
secrets = append(secrets, utils.SanitizeSecret(&secret, true).(corev1.Secret))
}
list.Items = secrets
responseObject = list
} else {
secret, _ := responseBody.(*corev1.Secret)
if secret != nil {
logging.Log.Debug("Processing Secret response")
responseObject = utils.SanitizeSecret(secret, true).(corev1.Secret)
} else {
responseObject = responseBody.(*metav1.Status)
}
}

var statusCode *int = new(int)
forwardResponse.StatusCode(statusCode)
response.Header().Add("Content-Type", restful.MIME_JSON)
response.WriteHeaderAndEntity(*statusCode, responseObject)
}
33 changes: 0 additions & 33 deletions pkg/endpoints/websocket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ func TestWebsocketResources(t *testing.T) {
taskRecord := NewInformerRecord(getKind(string(broadcaster.TaskCreated)), true)
clusterTaskRecord := NewInformerRecord(getKind(string(broadcaster.ClusterTaskCreated)), true)
extensionRecord := NewInformerRecord(getKind(string(broadcaster.ServiceExtensionCreated)), true)
secretRecord := NewInformerRecord(getKind(string(broadcaster.SecretCreated)), true)
// CD records
namespaceRecord := NewInformerRecord(getKind(string(broadcaster.NamespaceCreated)), false)

Expand All @@ -115,7 +114,6 @@ func TestWebsocketResources(t *testing.T) {
clusterTaskRecord.CRD: &clusterTaskRecord,
namespaceRecord.CRD: &namespaceRecord,
extensionRecord.CRD: &extensionRecord,
secretRecord.CRD: &secretRecord,
}

for i := 1; i <= clients; i++ {
Expand Down Expand Up @@ -148,7 +146,6 @@ func TestWebsocketResources(t *testing.T) {
// Create, Update, and Delete records
CUDTasks(r, t, installNamespace)
CUDClusterTasks(r, t)
CUDSecrets(r, t, installNamespace)
CUDExtensions(r, t, installNamespace)
// Create and Delete records
CDNamespaces(r, t)
Expand Down Expand Up @@ -344,36 +341,6 @@ func CUDExtensions(r *Resource, t *testing.T, namespace string) {
}
}

func CUDSecrets(r *Resource, t *testing.T, namespace string) {
resourceVersion := "1"

secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "secret",
ResourceVersion: resourceVersion,
},
}

_, err := r.K8sClient.CoreV1().Secrets(namespace).Create(&secret)
if err != nil {
t.Fatalf("Error creating secret: %s: %s\n", secret.Name, err.Error())
}

newVersion := "2"
secret.ResourceVersion = newVersion
t.Log("Updating secret")
_, err = r.K8sClient.CoreV1().Secrets(namespace).Update(&secret)
if err != nil {
t.Fatalf("Error updating secret: %s: %s\n", secret.Name, err.Error())
}

t.Log("Deleting secret")
err = r.K8sClient.CoreV1().Secrets(namespace).Delete(secret.Name, &metav1.DeleteOptions{})
if err != nil {
t.Fatalf("Error deleting secret: %s: %s\n", secret.Name, err.Error())
}
}

// CD functions

func CDNamespaces(r *Resource, t *testing.T) {
Expand Down
Loading

0 comments on commit 68a2682

Please sign in to comment.