Skip to content

Commit

Permalink
Add Namespaced Scope Interceptor
Browse files Browse the repository at this point in the history
Added Namespaced Scope Interceptor. A namespaced admin can create and
manage its interceptor without requiring elevated permissions. Fixes #1364
  • Loading branch information
khrm committed Oct 13, 2022
1 parent 811e571 commit c7156a3
Show file tree
Hide file tree
Showing 37 changed files with 2,910 additions and 26 deletions.
2 changes: 2 additions & 0 deletions cmd/controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/tektoncd/triggers/pkg/reconciler/clusterinterceptor"
elresources "github.com/tektoncd/triggers/pkg/reconciler/eventlistener/resources"
"github.com/tektoncd/triggers/pkg/reconciler/interceptor"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
Expand Down Expand Up @@ -95,5 +96,6 @@ func main() {
cfg,
eventlistener.NewController(c),
clusterinterceptor.NewController(),
interceptor.NewController(),
)
}
54 changes: 54 additions & 0 deletions config/300-interceptor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright 2022 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
#
# https://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.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: interceptors.triggers.tekton.dev
labels:
app.kubernetes.io/instance: default
app.kubernetes.io/part-of: tekton-triggers
triggers.tekton.dev/release: "devel"
version: "devel"
spec:
group: triggers.tekton.dev
scope: Cluster
names:
kind: Interceptor
plural: interceptors
singular: interceptor
shortNames:
- ni
categories:
- tekton
- tekton-triggers
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
# One can use x-kubernetes-preserve-unknown-fields: true
# at the root of the schema (and inside any properties, additionalProperties)
# to get the traditional CRD behaviour that nothing is pruned, despite
# setting spec.preserveUnknownProperties: false.
#
# See https://kubernetes.io/blog/2019/06/20/crd-structural-schema/
# See issue: https://github.com/knative/serving/issues/912
x-kubernetes-preserve-unknown-fields: true
# Opt into the status subresource so metadata.generation
# starts to increment
subresources:
status: {}
164 changes: 160 additions & 4 deletions docs/triggers-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ string
<h3 id="triggers.tekton.dev/v1alpha1.ClientConfig">ClientConfig
</h3>
<p>
(<em>Appears on:</em><a href="#triggers.tekton.dev/v1alpha1.ClusterInterceptorSpec">ClusterInterceptorSpec</a>)
(<em>Appears on:</em><a href="#triggers.tekton.dev/v1alpha1.ClusterInterceptorSpec">ClusterInterceptorSpec</a>, <a href="#triggers.tekton.dev/v1alpha1.InterceptorSpec">InterceptorSpec</a>)
</p>
<div>
<p>ClientConfig describes how a client can communicate with the Interceptor</p>
Expand Down Expand Up @@ -1182,6 +1182,79 @@ SecretRef
</tr>
</tbody>
</table>
<h3 id="triggers.tekton.dev/v1alpha1.Interceptor">Interceptor
</h3>
<div>
<p>Interceptor describes a pluggable interceptor including configuration
such as the fields it accepts and its deployment address. The type is based on
the Validating/MutatingWebhookConfiguration types for configuring AdmissionWebhooks</p>
</div>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>metadata</code><br/>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#objectmeta-v1-meta">
Kubernetes meta/v1.ObjectMeta
</a>
</em>
</td>
<td>
<em>(Optional)</em>
Refer to the Kubernetes API documentation for the fields of the
<code>metadata</code> field.
</td>
</tr>
<tr>
<td>
<code>spec</code><br/>
<em>
<a href="#triggers.tekton.dev/v1alpha1.InterceptorSpec">
InterceptorSpec
</a>
</em>
</td>
<td>
<br/>
<br/>
<table>
<tr>
<td>
<code>clientConfig</code><br/>
<em>
<a href="#triggers.tekton.dev/v1alpha1.ClientConfig">
ClientConfig
</a>
</em>
</td>
<td>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<code>status</code><br/>
<em>
<a href="#triggers.tekton.dev/v1alpha1.InterceptorStatus">
InterceptorStatus
</a>
</em>
</td>
<td>
<em>(Optional)</em>
</td>
</tr>
</tbody>
</table>
<h3 id="triggers.tekton.dev/v1alpha1.InterceptorInterface">InterceptorInterface
</h3>
<div>
Expand All @@ -1204,6 +1277,9 @@ SecretRef
<tbody><tr><td><p>&#34;ClusterInterceptor&#34;</p></td>
<td><p>ClusterInterceptorKind indicates that Interceptor type has a cluster scope.</p>
</td>
</tr><tr><td><p>&#34;NamespacedInterceptor&#34;</p></td>
<td><p>NamespacedInterceptorKind indicated that interceptor has a namespaced scope</p>
</td>
</tr></tbody>
</table>
<h3 id="triggers.tekton.dev/v1alpha1.InterceptorParams">InterceptorParams
Expand Down Expand Up @@ -1427,6 +1503,85 @@ Status
</tr>
</tbody>
</table>
<h3 id="triggers.tekton.dev/v1alpha1.InterceptorSpec">InterceptorSpec
</h3>
<p>
(<em>Appears on:</em><a href="#triggers.tekton.dev/v1alpha1.Interceptor">Interceptor</a>)
</p>
<div>
<p>InterceptorSpec describes the Spec for an Interceptor</p>
</div>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>clientConfig</code><br/>
<em>
<a href="#triggers.tekton.dev/v1alpha1.ClientConfig">
ClientConfig
</a>
</em>
</td>
<td>
</td>
</tr>
</tbody>
</table>
<h3 id="triggers.tekton.dev/v1alpha1.InterceptorStatus">InterceptorStatus
</h3>
<p>
(<em>Appears on:</em><a href="#triggers.tekton.dev/v1alpha1.Interceptor">Interceptor</a>)
</p>
<div>
<p>InterceptorStatus holds the status of the Interceptor</p>
</div>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>Status</code><br/>
<em>
<a href="https://pkg.go.dev/knative.dev/pkg/apis/duck/v1#Status">
knative.dev/pkg/apis/duck/v1.Status
</a>
</em>
</td>
<td>
<p>
(Members of <code>Status</code> are embedded into this type.)
</p>
</td>
</tr>
<tr>
<td>
<code>AddressStatus</code><br/>
<em>
<a href="https://pkg.go.dev/knative.dev/pkg/apis/duck/v1#AddressStatus">
knative.dev/pkg/apis/duck/v1.AddressStatus
</a>
</em>
</td>
<td>
<p>
(Members of <code>AddressStatus</code> are embedded into this type.)
</p>
<p>Interceptor is Addressable and exposes the URL where the Interceptor is running</p>
</td>
</tr>
</tbody>
</table>
<h3 id="triggers.tekton.dev/v1alpha1.KubernetesResource">KubernetesResource
</h3>
<p>
Expand Down Expand Up @@ -3612,6 +3767,9 @@ SecretRef
<tbody><tr><td><p>&#34;ClusterInterceptor&#34;</p></td>
<td><p>ClusterInterceptorKind indicates that Interceptor type has a cluster scope.</p>
</td>
</tr><tr><td><p>&#34;NamespacedInterceptor&#34;</p></td>
<td><p>NamespacedInterceptorKind indicates that Interceptor type has a namespace scope.</p>
</td>
</tr></tbody>
</table>
<h3 id="triggers.tekton.dev/v1beta1.InterceptorParams">InterceptorParams
Expand Down Expand Up @@ -3690,9 +3848,7 @@ InterceptorKind
</td>
<td>
<em>(Optional)</em>
<p>InterceptorKind indicates the kind of the Interceptor, namespaced or cluster scoped.
Currently only InterceptorKind is ClusterInterceptor, so the only valid value
is the default one</p>
<p>InterceptorKind indicates the kind of the Interceptor, namespaced or cluster scoped.</p>
</td>
</tr>
<tr>
Expand Down
39 changes: 33 additions & 6 deletions pkg/adapter/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"time"

clusterinterceptorsinformer "github.com/tektoncd/triggers/pkg/client/injection/informers/triggers/v1alpha1/clusterinterceptor"
interceptorsinformer "github.com/tektoncd/triggers/pkg/client/injection/informers/triggers/v1alpha1/interceptor"
clustertriggerbindingsinformer "github.com/tektoncd/triggers/pkg/client/injection/informers/triggers/v1beta1/clustertriggerbinding"
eventlistenerinformer "github.com/tektoncd/triggers/pkg/client/injection/informers/triggers/v1beta1/eventlistener"
triggersinformer "github.com/tektoncd/triggers/pkg/client/injection/informers/triggers/v1beta1/trigger"
Expand Down Expand Up @@ -108,7 +109,7 @@ func (s *sinker) getHTTPClient() (*http.Client, error) {

certPool := x509.NewCertPool()

err := s.getCertFromClusterInterceptor(certPool)
err := s.getCertFromInterceptor(certPool)
if err != nil {
return &http.Client{}, fmt.Errorf("Timed out waiting on CaBundle to available for clusterInterceptor: %v", err)
}
Expand All @@ -119,7 +120,7 @@ func (s *sinker) getHTTPClient() (*http.Client, error) {
go func() {
for {
<-ticker.C
if err := s.getCertFromClusterInterceptor(certPool); err != nil {
if err := s.getCertFromInterceptor(certPool); err != nil {
s.Logger.Fatalf("Timed out waiting on CaBundle to available for clusterInterceptor: %v", err)
}
}
Expand All @@ -141,7 +142,7 @@ func (s *sinker) getHTTPClient() (*http.Client, error) {
ExpectContinueTimeout: s.Args.ElHTTPClientExpectContinueTimeout * time.Second}}, nil
}

func (s *sinker) getCertFromClusterInterceptor(certPool *x509.CertPool) error {
func (s *sinker) getCertFromInterceptor(certPool *x509.CertPool) error {
var (
caCert []byte
count int
Expand All @@ -166,10 +167,35 @@ func (s *sinker) getCertFromClusterInterceptor(certPool *x509.CertPool) error {
}
}
}
if httpsCILen != 0 && httpsCILen == count {
return true, nil
if httpsCILen == 0 || httpsCILen != count {
return false, fmt.Errorf("empty caBundle in clusterInterceptor spec")
}
return false, fmt.Errorf("empty caBundle in clusterInterceptor spec")

httpsCILen = 0
count = 0

interceptorList, err := interceptorsinformer.Get(s.injCtx).Lister().Interceptors(s.Namespace).List(labels.Everything())
if err != nil {
return false, err
}

for i := range interceptorList {
if v, k := clusterInterceptorList[i].Labels["server/type"]; k && v == "https" {
httpsCILen++
if !bytes.Equal(interceptorList[i].Spec.ClientConfig.CaBundle, []byte{}) {
caCert = interceptorList[i].Spec.ClientConfig.CaBundle
if ok := certPool.AppendCertsFromPEM(caCert); !ok {
return false, fmt.Errorf("unable to parse cert from %s", caCert)
}
count++
}
}
}
if httpsCILen != count {
return false, fmt.Errorf("empty caBundle in interceptor spec")
}

return true, nil
}); err != nil {
return fmt.Errorf("Timed out waiting on CaBundle to available for clusterInterceptor: %v", err)
}
Expand Down Expand Up @@ -206,6 +232,7 @@ func (s *sinker) Start(ctx context.Context) error {
ClusterTriggerBindingLister: clustertriggerbindingsinformer.Get(s.injCtx).Lister(),
TriggerTemplateLister: triggertemplatesinformer.Get(s.injCtx).Lister(),
ClusterInterceptorLister: clusterinterceptorsinformer.Get(s.injCtx).Lister(),
InterceptorLister: interceptorsinformer.Get(s.injCtx).Lister(),
}

mux := http.NewServeMux()
Expand Down
33 changes: 33 additions & 0 deletions pkg/apis/triggers/v1alpha1/interceptor_defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Copyright 2022 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 v1alpha1

import (
"context"

"github.com/tektoncd/triggers/pkg/apis/triggers/contexts"
)

// SetDefaults sets the defaults on the object.
func (it *Interceptor) SetDefaults(ctx context.Context) {
if !contexts.IsUpgradeViaDefaulting(ctx) {
return
}
if _, ok := it.GetLabels()["server/type"]; !ok {
// if server type is not set its assumed that running server is http
it.Labels = map[string]string{
"server/type": "http",
}
}
}
Loading

0 comments on commit c7156a3

Please sign in to comment.