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

Support for fetching annotations from external source to render config templates #51

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
94 changes: 94 additions & 0 deletions pkg/extdataservice/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package extdataservice

import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
v1 "k8s.io/api/admission/v1"
"net"
"net/http"
"net/url"
"strings"
)

const (
Endpoint = "/"
)

type ExtDataClient struct {
client *http.Client
url *url.URL
}

func NewClient(apiUrl string, tlsConfig *tls.Config) (*ExtDataClient, error) {
parsedApiUrl, err := url.Parse(apiUrl)
if err != nil {
return nil, err
}
// Code path won't execute for localhost/sidecar call
if needsTLS(parsedApiUrl) && tlsConfig != nil {
return &ExtDataClient{client: &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
TLSNextProto: nil,
}}, url: parsedApiUrl}, nil
}
return &ExtDataClient{client: &http.Client{}, url: parsedApiUrl}, nil
}

type ExtDataResponse struct {
Annotations map[string]string
}

type ExtDataRequest struct {
AdmissionReview v1.AdmissionReview
}

func (c *ExtDataClient) FetchExtData(request *ExtDataRequest) (*ExtDataResponse, error) {
requestBody, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("error encoding request payload: %v", err)
}
req, err := http.NewRequest("GET", c.url.String()+Endpoint, bytes.NewBuffer(requestBody))
if err != nil {
return nil, fmt.Errorf("error creating request: %v", err)
}
resp, err := c.client.Do(req)
if err != nil {
return nil, fmt.Errorf("error sending request: %v", err.Error())
}

defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error failed with status code %v", resp.StatusCode)
}
var extAnnotationResponse ExtDataResponse
err = json.NewDecoder(resp.Body).Decode(&extAnnotationResponse)
if err != nil {
return nil, fmt.Errorf("error decoding response: %v", err)
}
return &extAnnotationResponse, nil
}

func needsTLS(apiUrl *url.URL) bool {
if !isLocalhost(apiUrl) {
return true
}
return false
}

func isLocalhost(u *url.URL) bool {
// Split the Host into host and port
host, _, err := net.SplitHostPort(u.Host)
if err != nil {
// If SplitHostPort fails, it might not have a port
host = u.Host
}

// Convert host to lowercase for case-insensitive comparison
host = strings.ToLower(host)

// Check if it's localhost or an IP loopback address
return host == "localhost" || host == "127.0.0.1" || host == "::1"
}
1 change: 1 addition & 0 deletions pkg/injectionwebhook/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type WebhookConfig struct {
CaFilePath string `long:"ca-file-path" required:"false" description:"file containing the CA cert"`
SidecarConfigFile string `long:"sidecar-config-file" required:"true" description:"file containing the sidecar container configuration"`
MutationConfigFile string `long:"mutation-config-file" required:"true" description:"file containing the mutation configuration"`
ExtDataUrl string `long:"ext-annotation-gen" required:"false" description:"url for fetching external data"`
BuildInfoLabels string `long:"build-info-labels" required:"false" description:"additional build info metric labels"`

// Flag to permit fallback to old, insecure TLS configurations.
Expand Down
34 changes: 33 additions & 1 deletion pkg/injectionwebhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"crypto/x509"
"encoding/json"
"fmt"
"github.com/salesforce/generic-sidecar-injector/pkg/extdataservice"
"io/ioutil"
"net/http"
"strings"
Expand Down Expand Up @@ -88,6 +89,7 @@ type WebhookServer struct {
sidecarConfigTemplate *template.Template
mutatingConfig *mutationconfig.MutationConfigs
certificateReloader util.CertificateReloader
extDataClient *extdataservice.ExtDataClient
}

// NewWebhookServer is a constructor for webhookServer
Expand Down Expand Up @@ -122,9 +124,30 @@ func (whsvr *WebhookServer) mutate(ar *v1.AdmissionReview) (admissionResponse *v
glog.Errorf("api=mutate, message=new AdmissionReview, Kind=%v, Namespace=%v, Name=%v (%v), UID=%v, patchOperation=%v, UserInfo=%v",
req.Kind, req.Namespace, req.Name, pod.Name, req.UID, req.Operation, req.UserInfo)

renderTemplateAnnotations := make(map[string]string)
for k, v := range pod.Annotations {
renderTemplateAnnotations[k] = v
}
if whsvr.extDataClient != nil {
extDataResponse, err := whsvr.extDataClient.FetchExtData(&extdataservice.ExtDataRequest{AdmissionReview: *ar})
if err != nil {
glog.Errorf("api=mutate, reason=extAnnotationClient, message=error fetching ext annotations, err=%v", err)
return &v1.AdmissionResponse{
Result: &metav1.Status{
Message: err.Error(),
},
}, nil
}
// Will override actual pod annotation if exists with same key
for k, v := range extDataResponse.Annotations {
renderTemplateAnnotations[k] = v
}
}

sidecarConfig, err := sidecarconfig.RenderTemplate(corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: pod.Annotations,
Labels: pod.Labels,
Annotations: renderTemplateAnnotations,
},
Spec: corev1.PodSpec{
ServiceAccountName: pod.Spec.ServiceAccountName,
Expand Down Expand Up @@ -313,6 +336,15 @@ func (whsvr *WebhookServer) Start() (chan bool, chan bool, error) {
}
whsvr.tlsServer.Handler = router

if whsvr.config.ExtDataUrl != "" {
extDataClient, err := extdataservice.NewClient(whsvr.config.ExtDataUrl, tlsConfig)
if err != nil {
glog.Errorf("api=Start, reason=extdataservice.NewClient, url=%v, err=%v", whsvr.config.ExtDataUrl, err)
return nil, nil, errors.Errorf("api=Start, reason=extdataservice.NewClient, url=%v, err=%v", whsvr.config.ExtDataUrl, err)
}
whsvr.extDataClient = extDataClient
}

// Channel to indicate when the server stopped listening for some reason
doneListeningTLSChannel := make(chan bool)

Expand Down
Binary file modified sidecarinjector
Binary file not shown.