Skip to content

Commit

Permalink
Merge pull request #175 from nginxinc/jwt
Browse files Browse the repository at this point in the history
Add support for JWT for NGINX Plus
  • Loading branch information
pleshakov authored Aug 28, 2017
2 parents 6065c9e + 239fd88 commit b8e7dcb
Show file tree
Hide file tree
Showing 15 changed files with 328 additions and 97 deletions.
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

0 comments on commit b8e7dcb

Please sign in to comment.