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

Add support for JWT for NGINX Plus #175

Merged
merged 1 commit into from
Aug 28, 2017
Merged
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
4 changes: 2 additions & 2 deletions nginx-controller/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ COPY nginx-ingress nginx/templates/nginx.ingress.tmpl nginx/templates/nginx.tmpl

RUN rm /etc/nginx/conf.d/*

RUN mkdir -p /etc/nginx/ssl
ADD default.pem /etc/nginx/ssl
RUN mkdir -p /etc/nginx/secrets
ADD default.pem /etc/nginx/secrets/default

ENTRYPOINT ["/nginx-ingress"]
4 changes: 2 additions & 2 deletions nginx-controller/DockerfileForAlpine
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ COPY nginx-ingress nginx/templates/nginx.ingress.tmpl nginx/templates/nginx.tmpl

RUN rm /etc/nginx/conf.d/*

RUN mkdir -p /etc/nginx/ssl
ADD default.pem /etc/nginx/ssl
RUN mkdir -p /etc/nginx/secrets
ADD default.pem /etc/nginx/secrets/default

ENTRYPOINT ["/nginx-ingress"]
7 changes: 2 additions & 5 deletions nginx-controller/DockerfileForPlus
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,10 @@ EXPOSE 80 443 8080
RUN ln -sf /proc/1/fd/1 /var/log/nginx/access.log \
&& ln -sf /proc/1/fd/2 /var/log/nginx/error.log

# nginx will store lists of upstream servers in this directory
RUN mkdir -p /var/lib/nginx/state && chown -R nginx:nginx /var/lib/nginx

COPY nginx-ingress nginx/templates/nginx-plus.ingress.tmpl nginx/templates/nginx-plus.tmpl /
RUN rm /etc/nginx/conf.d/*

RUN mkdir -p /etc/nginx/ssl
ADD default.pem /etc/nginx/ssl
RUN mkdir -p /etc/nginx/secrets
ADD default.pem /etc/nginx/secrets/default

ENTRYPOINT ["/nginx-ingress"]
69 changes: 58 additions & 11 deletions nginx-controller/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,16 @@ func NewLoadBalancerController(kubeClient kubernetes.Interface, resyncPeriod tim
return
}
}
if err := ValidateTLSSecret(remSecr); err != nil {
if err := lbc.ValidateSecret(remSecr); err != nil {
return
}

glog.V(3).Infof("Removing Secret: %v", remSecr.Name)
lbc.syncQueue.enqueue(obj)
},
UpdateFunc: func(old, cur interface{}) {
errOld := ValidateTLSSecret(old.(*api_v1.Secret))
errCur := ValidateTLSSecret(cur.(*api_v1.Secret))
errOld := lbc.ValidateSecret(old.(*api_v1.Secret))
errCur := lbc.ValidateSecret(cur.(*api_v1.Secret))
if errOld != nil && errCur != nil {
return
}
Expand Down Expand Up @@ -671,7 +671,7 @@ func (lbc *LoadBalancerController) syncSecret(task Task) {
if !secrExists {
glog.V(2).Infof("Deleting Secret: %v\n", key)

if err := lbc.cnf.DeleteTLSSecret(key, ings); err != nil {
if err := lbc.cnf.DeleteSecret(key, ings); err != nil {
glog.Errorf("Error when deleting Secret: %v: %v", key, err)
}

Expand All @@ -689,7 +689,7 @@ func (lbc *LoadBalancerController) syncSecret(task Task) {
secret := obj.(*api_v1.Secret)

if key == lbc.defaultServerSecret {
err := ValidateTLSSecret(secret)
err := nginx.ValidateTLSSecret(secret)
if err != nil {
glog.Errorf("Couldn't validate the default server Secret %v: %v", key, err)
lbc.recorder.Eventf(secret, api_v1.EventTypeWarning, "Rejected", "the default server Secret %v was rejected, using the previous version: %v", key, err)
Expand All @@ -706,10 +706,10 @@ func (lbc *LoadBalancerController) syncSecret(task Task) {
}

if len(ings) > 0 {
err := ValidateTLSSecret(secret)
err := lbc.ValidateSecret(secret)
if err != nil {
glog.Errorf("Couldn't validate secret %v: %v", key, err)
if err := lbc.cnf.DeleteTLSSecret(key, ings); err != nil {
if err := lbc.cnf.DeleteSecret(key, ings); err != nil {
glog.Errorf("Error when deleting Secret: %v: %v", key, err)
}
for _, ing := range ings {
Expand All @@ -720,7 +720,7 @@ func (lbc *LoadBalancerController) syncSecret(task Task) {
return
}

if err := lbc.cnf.AddOrUpdateTLSSecret(secret, true); err != nil {
if err := lbc.cnf.AddOrUpdateSecret(secret); err != nil {
glog.Errorf("Error when updating Secret %v: %v", key, err)
lbc.recorder.Eventf(secret, api_v1.EventTypeWarning, "UpdatedWithError", "%v was updated, but not applied: %v", key, err)
for _, ing := range ings {
Expand All @@ -742,13 +742,23 @@ func (lbc *LoadBalancerController) findIngressesForSecret(secret string) ([]exte
if err != nil {
return nil, fmt.Errorf("Couldn't get the list of Ingress resources: %v", err)
}

items:
for _, ing := range ings.Items {
if !isNginxIngress(&ing) {
continue
}
for _, tls := range ing.Spec.TLS {
if tls.SecretName == secret {
res = append(res, ing)
continue items
}
}
if lbc.nginxPlus {
if jwtKey, exists := ing.Annotations[nginx.JWTKeyAnnotation]; exists {
if jwtKey == secret {
res = append(res, ing)
}
}
}
}
Expand Down Expand Up @@ -795,18 +805,36 @@ func (lbc *LoadBalancerController) createIngress(ing *extensions.Ingress) (*ngin
Ingress: ing,
}

ingEx.Secrets = make(map[string]*api_v1.Secret)
ingEx.TLSSecrets = make(map[string]*api_v1.Secret)
for _, tls := range ing.Spec.TLS {
secretName := tls.SecretName
secret, err := lbc.client.Core().Secrets(ing.Namespace).Get(secretName, meta_v1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("Error retrieving secret %v for Ingress %v: %v", secretName, ing.Name, err)
}
err = ValidateTLSSecret(secret)
err = nginx.ValidateTLSSecret(secret)
if err != nil {
return nil, fmt.Errorf("Error validating secret %v for Ingress %v: %v", secretName, ing.Name, err)
}
ingEx.Secrets[secretName] = secret
ingEx.TLSSecrets[secretName] = secret
}

if lbc.nginxPlus {
if jwtKey, exists := ingEx.Ingress.Annotations[nginx.JWTKeyAnnotation]; exists {
secretName := jwtKey

secret, err := lbc.client.Core().Secrets(ing.Namespace).Get(secretName, meta_v1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("Error retrieving secret %v for Ingress %v: %v", secretName, ing.Name, err)
}

err = nginx.ValidateJWKSecret(secret)
if err != nil {
return nil, fmt.Errorf("Error validating secret %v for Ingress %v: %v", secretName, ing.Name, err)
}

ingEx.JWTKey = secret
}
}

ingEx.Endpoints = make(map[string][]string)
Expand Down Expand Up @@ -950,6 +978,8 @@ func (lbc *LoadBalancerController) getServiceForIngressBackend(backend *extensio
return nil, fmt.Errorf("service %s doesn't exists", svcKey)
}

// ParseNamespaceName parses the string in the <namespace>/<name> format and returns the name and the namespace.
// It returns an error in case the string does not follow the <namespace>/<name> format.
func ParseNamespaceName(value string) (ns string, name string, err error) {
res := strings.Split(value, "/")
if len(res) != 2 {
Expand All @@ -965,3 +995,20 @@ func isNginxIngress(ing *extensions.Ingress) bool {

return true
}

// ValidateSecret validates that the secret follows the TLS Secret format.
// For NGINX Plus, it also checks if the secret follows the JWK Secret format.
func (lbc *LoadBalancerController) ValidateSecret(secret *api_v1.Secret) error {
err1 := nginx.ValidateTLSSecret(secret)
if !lbc.nginxPlus {
return err1
}

err2 := nginx.ValidateJWKSecret(secret)

if err1 == nil || err2 == nil {
return nil
}

return fmt.Errorf("Secret is not a TLS or JWK secret")
}
20 changes: 0 additions & 20 deletions nginx-controller/controller/secret.go

This file was deleted.

6 changes: 3 additions & 3 deletions nginx-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var (
defaultServerSecret = flag.String("default-server-tls-secret", "",
`Specifies a secret with a TLS certificate and key for SSL termination of
the default server. The value must follow the following format: <namespace>/<name>.
If not specified, the key and the cert from /etc/nginx/default.pem is used.`)
If not specified, the key and the cert from /etc/nginx/default is used.`)
)

func main() {
Expand Down Expand Up @@ -100,13 +100,13 @@ func main() {
if err != nil {
glog.Fatalf("Error when getting %v: %v", *defaultServerSecret, err)
}
err = controller.ValidateTLSSecret(secret)
err = nginx.ValidateTLSSecret(secret)
if err != nil {
glog.Fatalf("%v is invalid: %v", *defaultServerSecret, err)
}

bytes := nginx.GenerateCertAndKeyFileContent(secret)
ngxc.AddOrUpdatePemFile(nginx.DefaultServerPemName, bytes)
ngxc.AddOrUpdateSecretFile(nginx.DefaultServerSecretName, bytes, nginx.TLSSecretFileMode)
}

nginxDone := make(chan error, 1)
Expand Down
5 changes: 5 additions & 0 deletions nginx-controller/nginx/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ type Config struct {
MainServerSSLPreferServerCiphers bool
MainServerSSLCiphers string
MainServerSSLDHParam string

JWTRealm string
JWTKey string
JWTToken string
JWTLoginURL string
}

// NewDefaultConfig creates a Config with default values
Expand Down
Loading