Skip to content

Commit

Permalink
Add access control policy for VirtualServer
Browse files Browse the repository at this point in the history
* Add new CRD - Policy
* Implement access control policy
* Refactor return and redirect actions to work with access control
policy
* Support Policy CRD in Helm
  • Loading branch information
pleshakov committed Jul 2, 2020
1 parent d89b677 commit a3a109a
Show file tree
Hide file tree
Showing 42 changed files with 2,573 additions and 98 deletions.
56 changes: 56 additions & 0 deletions deployments/common/policy-definition.yaml
@@ -0,0 +1,56 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policies.k8s.nginx.org
spec:
group: k8s.nginx.org
versions:
- name: v1alpha1
served: true
storage: true
scope: Namespaced
names:
plural: policies
singular: policy
kind: Policy
shortNames:
- pol
preserveUnknownFields: false
validation:
openAPIV3Schema:
description: Policy defines a Policy for VirtualServer and VirtualServerRoute
resources.
type: object
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: 'PolicySpec is the spec of the Policy resource. The spec includes
multiple fields, where each field represents a different policy. Note:
currently we have only one policy -- AccessControl, but we will support
more in the future. Only one policy (field) is allowed.'
type: object
properties:
accessControl:
description: AccessControl defines an access policy based on the source
IP of a request.
type: object
properties:
allow:
type: array
items:
type: string
deny:
type: array
items:
type: string
11 changes: 11 additions & 0 deletions deployments/common/vs-definition.yaml
Expand Up @@ -63,6 +63,17 @@ spec:
type: string
ingressClassName:
type: string
policies:
type: array
items:
description: PolicyReference references a policy by name and an optional
namespace.
type: object
properties:
name:
type: string
namespace:
type: string
routes:
type: array
items:
Expand Down
60 changes: 60 additions & 0 deletions deployments/helm-chart/crds/policy.yaml
@@ -0,0 +1,60 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policies.k8s.nginx.org
labels:
app.kubernetes.io/name: "nginx-ingress"
annotations:
"helm.sh/hook": crd-install
spec:
group: k8s.nginx.org
versions:
- name: v1alpha1
served: true
storage: true
scope: Namespaced
names:
plural: policies
singular: policy
kind: Policy
shortNames:
- pol
preserveUnknownFields: false
validation:
openAPIV3Schema:
description: Policy defines a Policy for VirtualServer and VirtualServerRoute
resources.
type: object
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: 'PolicySpec is the spec of the Policy resource. The spec includes
multiple fields, where each field represents a different policy. Note:
currently we have only one policy -- AccessControl, but we will support
more in the future. Only one policy (field) is allowed.'
type: object
properties:
accessControl:
description: AccessControl defines an access policy based on the source
IP of a request.
type: object
properties:
allow:
type: array
items:
type: string
deny:
type: array
items:
type: string
11 changes: 11 additions & 0 deletions deployments/helm-chart/crds/virtualserver.yaml
Expand Up @@ -67,6 +67,17 @@ spec:
type: string
ingressClassName:
type: string
policies:
type: array
items:
description: PolicyReference references a policy by name and an optional
namespace.
type: object
properties:
name:
type: string
namespace:
type: string
routes:
type: array
items:
Expand Down
1 change: 1 addition & 0 deletions deployments/helm-chart/templates/rbac.yaml
Expand Up @@ -73,6 +73,7 @@ rules:
- virtualservers
- virtualserverroutes
- transportservers
- policies
verbs:
- list
- watch
Expand Down
1 change: 1 addition & 0 deletions deployments/rbac/rbac.yaml
Expand Up @@ -66,6 +66,7 @@ rules:
- virtualserverroutes
- globalconfigurations
- transportservers
- policies
verbs:
- list
- watch
Expand Down
19 changes: 19 additions & 0 deletions internal/configs/configurator.go
Expand Up @@ -204,6 +204,25 @@ func (cnf *Configurator) addOrUpdateVirtualServer(virtualServerEx *VirtualServer
return warnings, nil
}

// AddOrUpdateVirtualServers adds or updates NGINX configuration for multiple VirtualServer resources.
func (cnf *Configurator) AddOrUpdateVirtualServers(virtualServerExes []*VirtualServerEx) (Warnings, error) {
allWarnings := newWarnings()

for _, vsEx := range virtualServerExes {
warnings, err := cnf.addOrUpdateVirtualServer(vsEx)
if err != nil {
return allWarnings, err
}
allWarnings.Add(warnings)
}

if err := cnf.nginxManager.Reload(); err != nil {
return allWarnings, fmt.Errorf("Error when reloading NGINX when updating Policy: %v", err)
}

return allWarnings, nil
}

// AddOrUpdateTransportServer adds or updates NGINX configuration for the TransportServer resource.
// It is a responsibility of the caller to check that the TransportServer references an existing listener.
func (cnf *Configurator) AddOrUpdateTransportServer(transportServerEx *TransportServerEx) error {
Expand Down
11 changes: 11 additions & 0 deletions internal/configs/version1/nginx-plus.tmpl
Expand Up @@ -178,6 +178,17 @@ http {

include /etc/nginx/config-version.conf;
include /etc/nginx/conf.d/*.conf;

server {
listen unix:/var/lib/nginx/nginx-418-server.sock;
access_log off;

{{if .OpenTracingEnabled}}
opentracing off;
{{end}}

return 418;
}
}

stream {
Expand Down
15 changes: 12 additions & 3 deletions internal/configs/version1/nginx.tmpl
Expand Up @@ -165,9 +165,18 @@ http {
opentracing off;
{{end}}

location / {
return 502;
}
return 502;
}

server {
listen unix:/var/lib/nginx/nginx-418-server.sock;
access_log off;

{{if .OpenTracingEnabled}}
opentracing off;
{{end}}

return 418;
}
}

Expand Down
14 changes: 12 additions & 2 deletions internal/configs/version2/http.go
Expand Up @@ -46,9 +46,13 @@ type Server struct {
InternalRedirectLocations []InternalRedirectLocation
Locations []Location
ErrorPageLocations []ErrorPageLocation
ReturnLocations []ReturnLocation
HealthChecks []HealthCheck
TLSRedirect *TLSRedirect
TLSPassthrough bool
Allow []string
Deny []string
PoliciesErrorReturn *Return
}

// SSL defines SSL configuration for a server.
Expand Down Expand Up @@ -86,10 +90,16 @@ type Location struct {
AddHeaders []AddHeader
Rewrites []string
HasKeepalive bool
DefaultType string
Return *Return
ErrorPages []ErrorPage
ProxySSLName string
InternalProxyPass string
}

// ReturnLocation defines a location for returning a fixed response.
type ReturnLocation struct {
Name string
DefaultType string
Return Return
}

// SplitClient defines a split_clients.
Expand Down
48 changes: 36 additions & 12 deletions internal/configs/version2/nginx-plus.virtualserver.tmpl
Expand Up @@ -92,6 +92,24 @@ server {
real_ip_recursive on;
{{ end }}

{{ with $s.PoliciesErrorReturn }}
return {{ .Code }};
{{ end }}

{{ range $allow := $s.Allow }}
allow {{ $allow }};
{{ end }}
{{ if gt (len $s.Allow) 0 }}
deny all;
{{ end }}

{{ range $deny := $s.Deny }}
deny {{ $deny }};
{{ end }}
{{ if gt (len $s.Deny) 0 }}
allow all;
{{ end }}

{{ range $snippet := $s.Snippets }}
{{ $snippet }}
{{ end }}
Expand Down Expand Up @@ -129,6 +147,14 @@ server {
}
{{ end }}

{{ range $l := $s.ReturnLocations }}
location {{ $l.Name }} {
default_type "{{ $l.DefaultType }}";
# status code is ignored here, using 0
return 0 "{{ $l.Return.Text }}";
}
{{ end }}

{{ range $l := $s.Locations }}
location {{ $l.Path }} {
{{ if $l.Internal }}
Expand All @@ -138,18 +164,19 @@ server {
{{ $snippet }}
{{ end }}

{{ with $l.Return }}
{{ if $l.DefaultType }}
default_type "{{ $l.DefaultType }}";
{{ end }}
return {{ .Code }} "{{ .Text }}";
{{ range $e := $l.ErrorPages }}
error_page {{ $e.Codes }} {{ if ne 0 $e.ResponseCode }}={{ $e.ResponseCode }}{{ end }} "{{ $e.Name }}";
{{ end }}

{{ if $l.ProxyPass }}
{{ range $e := $l.ErrorPages }}
error_page {{ $e.Codes }} {{ if ne 0 $e.ResponseCode }}={{ $e.ResponseCode }}{{ end }} "{{ $e.Name }}";
{{ end }}
{{ if $l.ProxyInterceptErrors }}
proxy_intercept_errors on;
{{ end }}

{{ if $l.InternalProxyPass }}
proxy_pass {{ $l.InternalProxyPass }};
{{ end }}

{{ if $l.ProxyPass }}
set $default_connection_header {{ if $l.HasKeepalive }}""{{ else }}close{{ end }};

{{ range $r := $l.Rewrites }}
Expand All @@ -171,9 +198,6 @@ server {
{{ if $l.ProxyBufferSize }}
proxy_buffer_size {{ $l.ProxyBufferSize }};
{{ end }}
{{ if $l.ProxyInterceptErrors }}
proxy_intercept_errors on;
{{ end }}
proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;
Expand Down

0 comments on commit a3a109a

Please sign in to comment.