Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
HTTP trigger: TLS with existing certificates (#679)
Browse files Browse the repository at this point in the history
* HTTP trigger: add support for TLS with private key and cert

* documentation for tls with key and cert

* addressing review comment
  • Loading branch information
murali-reddy authored Apr 9, 2018
1 parent 68b140f commit d94d0e2
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 2 deletions.
10 changes: 10 additions & 0 deletions cmd/kubeless/trigger/http/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ var createCmd = &cobra.Command{
}
httpTrigger.Spec.TLSAcme = enableTLSAcme

tlsSecret, err := cmd.Flags().GetString("tls-secret")
if err != nil {
logrus.Fatal(err)
}
if enableTLSAcme && len(tlsSecret) > 0 {
logrus.Fatalf("Cannot specify both --enableTLSAcme and --tls-secret")
}
httpTrigger.Spec.TLSSecret = tlsSecret

hostName, err := cmd.Flags().GetString("hostname")
if err != nil {
logrus.Fatal(err)
Expand Down Expand Up @@ -132,5 +141,6 @@ func init() {
createCmd.Flags().BoolP("enableTLSAcme", "", false, "If true, routing rule will be configured for use with kube-lego")
createCmd.Flags().StringP("gateway", "", "", "Specify a valid gateway for the Ingress")
createCmd.Flags().StringP("basic-auth-secret", "", "", "Specify an existing secret name for basic authentication")
createCmd.Flags().StringP("tls-secret", "", "", "Specify an existing secret that contains a TLS private key and certificate to secure ingress")
createCmd.MarkFlagRequired("function-name")
}
11 changes: 10 additions & 1 deletion cmd/kubeless/trigger/http/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ var updateCmd = &cobra.Command{
}
httpTrigger.Spec.TLSAcme = enableTLSAcme

tlsSecret, err := cmd.Flags().GetString("tls-secret")
if err != nil {
logrus.Fatal(err)
}
if enableTLSAcme && len(tlsSecret) > 0 {
logrus.Fatalf("Cannot specify both --enableTLSAcme and --tls-secret")
}
httpTrigger.Spec.TLSSecret = tlsSecret

gateway, err := cmd.Flags().GetString("gateway")
if err != nil {
logrus.Fatal(err)
Expand Down Expand Up @@ -112,5 +121,5 @@ func init() {
updateCmd.Flags().BoolP("enableTLSAcme", "", false, "If true, routing rule will be configured for use with kube-lego")
updateCmd.Flags().StringP("gateway", "", "", "Specify a valid gateway for the Ingress")
updateCmd.Flags().StringP("basic-auth-secret", "", "", "Specify an existing secret name for basic authentication")

updateCmd.Flags().StringP("tls-secret", "", "", "Specify an existing secret that contains a TLS private key and certificate to secure ingress")
}
14 changes: 13 additions & 1 deletion docs/http-triggers.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,26 @@ $ curl --data '{"Another": "Echo"}' \

## Enable TLS

By default, Kubeless doesn't take care of setting up TLS for its functions. You can do it manually by following the [standard procedure](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) of securing ingress. There is also a [general guideline](https://docs.bitnami.com/kubernetes/how-to/secure-kubernetes-services-with-ingress-tls-letsencrypt/) to enable TLS for your Kubernetes services using LetsEncrypt and Kube-lego written by Bitnami folks. When you have running Kube-lego, you can deploy function and create route with flag `--enableTLSAcme` enabled as below:
By default, Kubeless doesn't take care of setting up TLS for its functions. You can do it manually by following the [standard procedure](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) of securing ingress. There is also a [general guideline](https://docs.bitnami.com/kubernetes/how-to/secure-kubernetes-services-with-ingress-tls-letsencrypt/) to enable TLS for your Kubernetes services using LetsEncrypt and Kube-lego written by Bitnami folks.

### Using Let’s Encrypt’s CA

When you have running Kube-lego, you can deploy function and create route with flag `--enableTLSAcme` enabled as below:

```console
$ kubeless trigger http create get-python --function-name get-python --path get-python --enableTLSAcme
```

Running the above command, Kubeless will automatically create a ingress object with annotation `kubernetes.io/tls-acme: 'true'` set which will be used by Kube-lego to configure the service certificate.

### Using existing Certificate and Private Key

If you have existing certificate, you can use them to setup TLS for ingress, there by securing functions. You need to create a [secret](https://kubernetes.io/docs/concepts/configuration/secret/) using the TLS private key and certificate as per Kubernetes ingress TLS [guideline](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls). You can use created secret with kubeless CLI as below.

```console
kubeless trigger http create get-python --function-name get-python --path get-python --tls-secret secret-name
```

## Enable Basic Authentication

By default, Kubeless doesn't take care about securing its exposed functions.
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/kubeless/v1beta1/http_trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type HTTPTriggerSpec struct {
FunctionName string `json:"function-name"` // Name of the associated function
HostName string `json:"host-name"`
TLSAcme bool `json:"tls"`
TLSSecret string `json:"tls-secret"`
Path string `json:"path"`
BasicAuthSecret string `json:"basic-auth-secret"`
Gateway string `json:"gateway"`
Expand Down
14 changes: 14 additions & 0 deletions pkg/utils/k8sutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,20 @@ func CreateIngress(client kubernetes.Interface, httpTriggerObj *kubelessApi.HTTP
}
}

if len(httpTriggerObj.Spec.TLSSecret) > 0 && httpTriggerObj.Spec.TLSAcme {
return fmt.Errorf("Can not create ingress object from HTTP trigger spec with both TLSSecret and IngressTLS specified")
}

// secure an Ingress by specified secret that contains a TLS private key and certificate
if len(httpTriggerObj.Spec.TLSSecret) > 0 {
ingress.Spec.TLS = []v1beta1.IngressTLS{
{
SecretName: httpTriggerObj.Spec.TLSSecret,
Hosts: []string{httpTriggerObj.Spec.HostName},
},
}
}

// add annotations and TLS configuration for kube-lego
if httpTriggerObj.Spec.TLSAcme {
ingressAnnotations["kubernetes.io/tls-acme"] = "true"
Expand Down
40 changes: 40 additions & 0 deletions script/libtest.bash
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,30 @@ create_basic_auth_secret() {
htpasswd -cb basic-auth foo bar
kubectl create secret generic $secret --from-file=basic-auth
}
create_tls_secret_from_key_cert() {
local secret=${1:?}; shift
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=foo.bar.com"
kubectl create secret tls $secret --key /tmp/tls.key --cert /tmp/tls.crt
}
create_http_trigger_with_tls_secret(){
local func=${1:?}; shift
local domain=${1-""};
local subpath=${2-""};
local secret=${3-""};
delete_http_trigger ${func}
echo_info "TEST: Creating HTTP trigger"
local command="kubeless trigger http create ing-${func} --function-name ${func}"
if [ -n "$domain" ]; then
command="$command --hostname ${domain}"
fi
if [ -n "$subpath" ]; then
command="$command --path ${subpath}"
fi
if [ -n "$secret" ]; then
command="$command --tls-secret ${secret}"
fi
eval $command
}
create_http_trigger(){
local func=${1:?}; shift
local domain=${1-""};
Expand Down Expand Up @@ -404,6 +428,22 @@ verify_http_trigger_basic_auth(){
sleep 3
curl -vv --header "Host: $domain" -u $auth $ip\/$subpath | grep "${expected_response}"
}
verify_https_trigger(){
local func=${1:?}; shift
local ip=${1:?}; shift
local expected_response=${1:?}; shift
local domain=${1:?}; shift
local subpath=${1:-""};
kubeless trigger http list | grep ${func}
local -i cnt=${TEST_MAX_WAIT_SEC:?}
echo_info "Waiting for ingress to be ready..."
until kubectl get ingress | grep $func | grep "$domain" | awk '{print $3}' | grep "$ip"; do
((cnt=cnt-1)) || return 1
sleep 1
done
sleep 3
curl -k -vv --header "Host: $domain" https:\/\/$ip\/$subpath | grep "${expected_response}"
}
delete_http_trigger() {
local func=${1:?}; shift
kubeless trigger http list |grep -w ing-${func} && kubeless trigger http delete ing-${func} >& /dev/null || true
Expand Down
11 changes: 11 additions & 0 deletions tests/integration-tests-http.bats
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ load ../script/libtest
verify_clean_object ingress ing-get-python
}

@test "Create HTTP Trigger with TLS private key and certificate" {
deploy_function get-python
verify_function get-python
create_tls_secret_from_key_cert foo-secret
create_http_trigger_with_tls_secret get-python "foo.bar.com" "get-python" "foo-secret"
verify_https_trigger get-python $(minikube ip) "hello.*world" "foo.bar.com" "get-python"
delete_http_trigger get-python
verify_clean_object httptrigger ing-get-python
verify_clean_object ingress ing-get-python
}

@test "Create HTTP Trigger with basic auth" {
deploy_function get-python
verify_function get-python
Expand Down

0 comments on commit d94d0e2

Please sign in to comment.