Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
k8s-ingress
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
3
Merge Requests
3
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
uplex-varnish
k8s-ingress
Commits
04e83f7f
Commit
04e83f7f
authored
Jan 06, 2019
by
Geoff Simmons
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add ACL support.
parent
73c8e0ed
Changes
30
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
662 additions
and
23 deletions
+662
-23
varnishcfg-crd.yaml
deploy/varnishcfg-crd.yaml
+59
-0
types.go
pkg/apis/varnishingress/v1alpha1/types.go
+41
-0
zz_generated.deepcopy.go
pkg/apis/varnishingress/v1alpha1/zz_generated.deepcopy.go
+78
-1
clientset.go
pkg/client/clientset/versioned/clientset.go
+1
-1
doc.go
pkg/client/clientset/versioned/doc.go
+1
-1
clientset_generated.go
pkg/client/clientset/versioned/fake/clientset_generated.go
+1
-1
doc.go
pkg/client/clientset/versioned/fake/doc.go
+1
-1
register.go
pkg/client/clientset/versioned/fake/register.go
+1
-1
doc.go
pkg/client/clientset/versioned/scheme/doc.go
+1
-1
register.go
pkg/client/clientset/versioned/scheme/register.go
+1
-1
doc.go
.../clientset/versioned/typed/varnishingress/v1alpha1/doc.go
+1
-1
doc.go
...ntset/versioned/typed/varnishingress/v1alpha1/fake/doc.go
+1
-1
fake_varnishconfig.go
.../typed/varnishingress/v1alpha1/fake/fake_varnishconfig.go
+1
-1
fake_varnishingress_client.go
...arnishingress/v1alpha1/fake/fake_varnishingress_client.go
+1
-1
generated_expansion.go
...oned/typed/varnishingress/v1alpha1/generated_expansion.go
+1
-1
varnishconfig.go
.../versioned/typed/varnishingress/v1alpha1/varnishconfig.go
+1
-1
varnishingress_client.go
...ed/typed/varnishingress/v1alpha1/varnishingress_client.go
+1
-1
factory.go
pkg/client/informers/externalversions/factory.go
+1
-1
generic.go
pkg/client/informers/externalversions/generic.go
+1
-1
factory_interfaces.go
...externalversions/internalinterfaces/factory_interfaces.go
+1
-1
interface.go
...nt/informers/externalversions/varnishingress/interface.go
+1
-1
interface.go
...ers/externalversions/varnishingress/v1alpha1/interface.go
+1
-1
varnishconfig.go
...externalversions/varnishingress/v1alpha1/varnishconfig.go
+1
-1
expansion_generated.go
...nt/listers/varnishingress/v1alpha1/expansion_generated.go
+1
-1
varnishconfig.go
pkg/client/listers/varnishingress/v1alpha1/varnishconfig.go
+1
-1
ingress.go
pkg/controller/ingress.go
+62
-0
acl.tmpl
pkg/varnish/vcl/acl.tmpl
+26
-0
acl.golden
pkg/varnish/vcl/testdata/acl.golden
+58
-0
vcl.go
pkg/varnish/vcl/vcl.go
+152
-0
vcl_test.go
pkg/varnish/vcl/vcl_test.go
+164
-0
No files found.
deploy/varnishcfg-crd.yaml
View file @
04e83f7f
...
...
@@ -88,6 +88,65 @@ spec:
host-match
:
type
:
string
minLength
:
1
acl
:
type
:
array
minItems
:
1
items
:
type
:
object
required
:
-
name
-
addrs
properties
:
name
:
type
:
string
minLength
:
1
addrs
:
type
:
array
minItems
:
1
items
:
type
:
object
required
:
-
addr
properties
:
addr
:
type
:
string
pattern
:
'
^[^"]+$'
mask-bits
:
type
:
integer
minimum
:
0
maximum
:
128
negate
:
type
:
boolean
type
:
enum
:
-
whitelist
-
blacklist
type
:
string
fail-status
:
type
:
integer
minimum
:
100
maximum
:
599
comparand
:
type
:
string
pattern
:
"
^((client|server|local|remote)
\\
.ip|xff-(first|2ndlast)|req
\\
.http
\\
.[a-zA-Z0-9!#$%&'*+-.^_`|~]+)$"
conditions
:
type
:
array
minItems
:
1
items
:
type
:
object
required
:
-
comparand
-
regex
-
match
properties
:
comparand
:
type
:
string
pattern
:
"
^req
\\
.(url|http
\\
.[a-zA-Z0-9!#$%&'*+-.^_`|~]+)$"
regex
:
type
:
string
minLength
:
1
match
:
type
:
boolean
status
:
acceptedNames
:
kind
:
VarnishConfig
...
...
pkg/apis/varnishingress/v1alpha1/types.go
View file @
04e83f7f
...
...
@@ -52,6 +52,7 @@ type VarnishConfigSpec struct {
Services
[]
string
`json:"services,omitempty"`
SelfSharding
*
SelfShardSpec
`json:"self-sharding,omitempty"`
Auth
[]
AuthSpec
`json:"auth,omitempty"`
ACLs
[]
ACLSpec
`json:"acl,omitempty"`
}
// SelfShardSpec specifies self-sharding in a Varnish cluster.
...
...
@@ -98,6 +99,46 @@ type AuthCondition struct {
HostRegex
string
`json:"host-match,omitempty"`
}
// ACLSpec specifies whitelisting or blacklisting IP addresses against
// an access control list.
type
ACLSpec
struct
{
Name
string
`json:"name,omitempty"`
ACLType
ACLType
`json:"type,omitempty"`
Comparand
string
`json:"comparand,omitempty"`
FailStatus
*
int32
`json:"fail-status,omitempty"`
Addresses
[]
ACLAddress
`json:"addrs,omitempty"`
Conditions
[]
Condition
`json:"conditions,omitempty"`
}
// ACLAddress represents an entry in a VCL. If MaskBits is non-nil, it
// is a CIDR range. If Negate is true, use the '!' notation in the VCL
// ACL.
type
ACLAddress
struct
{
Address
string
`json:"addr,omitempty"`
MaskBits
*
int32
`json:"mask-bits,omitempty"`
Negate
bool
`json:"negate,omitempty"`
}
// Condition represents a term in a boolean expression -- match or
// non-match against a VCL object.
type
Condition
struct
{
Comparand
string
`json:"comparand,omitempty"`
Regex
string
`json:"regex,omitempty"`
Match
bool
`json:"match,omitempty"`
}
// ACLType classifies an ACL.
type
ACLType
string
const
(
// Whitelist means that the failure status is returned when an
// IP address does not match an ACL.
Whitelist
ACLType
=
"whitelist"
// Blacklist means that the failure status is returned when an
// IP address does match an ACL.
Blacklist
=
"blacklist"
)
// VarnishConfigStatus is the status for a VarnishConfig resource
// type VarnishConfigStatus struct {
// AvailableReplicas int32 `json:"availableReplicas"`
...
...
pkg/apis/varnishingress/v1alpha1/zz_generated.deepcopy.go
View file @
04e83f7f
// +build !ignore_autogenerated
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
@@ -34,6 +34,60 @@ import (
runtime
"k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func
(
in
*
ACLAddress
)
DeepCopyInto
(
out
*
ACLAddress
)
{
*
out
=
*
in
if
in
.
MaskBits
!=
nil
{
in
,
out
:=
&
in
.
MaskBits
,
&
out
.
MaskBits
*
out
=
new
(
int32
)
**
out
=
**
in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACLAddress.
func
(
in
*
ACLAddress
)
DeepCopy
()
*
ACLAddress
{
if
in
==
nil
{
return
nil
}
out
:=
new
(
ACLAddress
)
in
.
DeepCopyInto
(
out
)
return
out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func
(
in
*
ACLSpec
)
DeepCopyInto
(
out
*
ACLSpec
)
{
*
out
=
*
in
if
in
.
FailStatus
!=
nil
{
in
,
out
:=
&
in
.
FailStatus
,
&
out
.
FailStatus
*
out
=
new
(
int32
)
**
out
=
**
in
}
if
in
.
Addresses
!=
nil
{
in
,
out
:=
&
in
.
Addresses
,
&
out
.
Addresses
*
out
=
make
([]
ACLAddress
,
len
(
*
in
))
for
i
:=
range
*
in
{
(
*
in
)[
i
]
.
DeepCopyInto
(
&
(
*
out
)[
i
])
}
}
if
in
.
Conditions
!=
nil
{
in
,
out
:=
&
in
.
Conditions
,
&
out
.
Conditions
*
out
=
make
([]
Condition
,
len
(
*
in
))
copy
(
*
out
,
*
in
)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACLSpec.
func
(
in
*
ACLSpec
)
DeepCopy
()
*
ACLSpec
{
if
in
==
nil
{
return
nil
}
out
:=
new
(
ACLSpec
)
in
.
DeepCopyInto
(
out
)
return
out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func
(
in
*
AuthCondition
)
DeepCopyInto
(
out
*
AuthCondition
)
{
*
out
=
*
in
...
...
@@ -71,6 +125,22 @@ func (in *AuthSpec) DeepCopy() *AuthSpec {
return
out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func
(
in
*
Condition
)
DeepCopyInto
(
out
*
Condition
)
{
*
out
=
*
in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition.
func
(
in
*
Condition
)
DeepCopy
()
*
Condition
{
if
in
==
nil
{
return
nil
}
out
:=
new
(
Condition
)
in
.
DeepCopyInto
(
out
)
return
out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func
(
in
*
ProbeSpec
)
DeepCopyInto
(
out
*
ProbeSpec
)
{
*
out
=
*
in
...
...
@@ -199,6 +269,13 @@ func (in *VarnishConfigSpec) DeepCopyInto(out *VarnishConfigSpec) {
(
*
in
)[
i
]
.
DeepCopyInto
(
&
(
*
out
)[
i
])
}
}
if
in
.
ACLs
!=
nil
{
in
,
out
:=
&
in
.
ACLs
,
&
out
.
ACLs
*
out
=
make
([]
ACLSpec
,
len
(
*
in
))
for
i
:=
range
*
in
{
(
*
in
)[
i
]
.
DeepCopyInto
(
&
(
*
out
)[
i
])
}
}
return
}
...
...
pkg/client/clientset/versioned/clientset.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/doc.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/fake/clientset_generated.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/fake/doc.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/fake/register.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/scheme/doc.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/scheme/register.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/typed/varnishingress/v1alpha1/doc.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/typed/varnishingress/v1alpha1/fake/doc.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/typed/varnishingress/v1alpha1/fake/fake_varnishconfig.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/typed/varnishingress/v1alpha1/fake/fake_varnishingress_client.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/typed/varnishingress/v1alpha1/generated_expansion.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/typed/varnishingress/v1alpha1/varnishconfig.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/clientset/versioned/typed/varnishingress/v1alpha1/varnishingress_client.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/informers/externalversions/factory.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/informers/externalversions/generic.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/informers/externalversions/varnishingress/interface.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/informers/externalversions/varnishingress/v1alpha1/interface.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/informers/externalversions/varnishingress/v1alpha1/varnishconfig.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/listers/varnishingress/v1alpha1/expansion_generated.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/client/listers/varnishingress/v1alpha1/varnishconfig.go
View file @
04e83f7f
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
...
...
pkg/controller/ingress.go
View file @
04e83f7f
...
...
@@ -49,6 +49,8 @@ const (
ingressClassKey
=
"kubernetes.io/ingress.class"
annotationPrefix
=
"ingress.varnish-cache.org/"
varnishSvcKey
=
annotationPrefix
+
"varnish-svc"
defACLcomparand
=
"client.ip"
defACLfailStatus
=
uint16
(
403
)
)
func
(
worker
*
NamespaceWorker
)
getVarnishSvcForIng
(
...
...
@@ -309,6 +311,63 @@ func (worker *NamespaceWorker) configAuth(spec *vcl.Spec,
return
nil
}
func
(
worker
*
NamespaceWorker
)
configACL
(
spec
*
vcl
.
Spec
,
vcfg
*
vcr_v1alpha1
.
VarnishConfig
)
error
{
if
len
(
vcfg
.
Spec
.
ACLs
)
==
0
{
worker
.
log
.
Infof
(
"No ACL spec found for VarnishConfig %s/%s"
,
vcfg
.
Namespace
,
vcfg
.
Name
)
return
nil
}
spec
.
ACLs
=
make
([]
vcl
.
ACL
,
0
,
len
(
vcfg
.
Spec
.
ACLs
))
for
_
,
acl
:=
range
vcfg
.
Spec
.
ACLs
{
worker
.
log
.
Debugf
(
"VarnishConfig %s/%s configuring VCL ACL "
+
"from: %+v"
,
vcfg
.
Namespace
,
vcfg
.
Name
,
acl
)
vclACL
:=
vcl
.
ACL
{
Name
:
acl
.
Name
,
Addresses
:
make
([]
vcl
.
ACLAddress
,
0
,
len
(
acl
.
Addresses
)),
Conditions
:
make
([]
vcl
.
MatchTerm
,
0
,
len
(
acl
.
Conditions
)),
}
if
acl
.
Comparand
==
""
{
vclACL
.
Comparand
=
defACLcomparand
}
else
{
vclACL
.
Comparand
=
acl
.
Comparand
}
if
acl
.
ACLType
==
""
||
acl
.
ACLType
==
vcr_v1alpha1
.
Whitelist
{
vclACL
.
Whitelist
=
true
}
if
acl
.
FailStatus
==
nil
{
vclACL
.
FailStatus
=
defACLfailStatus
}
else
{
vclACL
.
FailStatus
=
uint16
(
*
acl
.
FailStatus
)
}
for
_
,
addr
:=
range
acl
.
Addresses
{
vclAddr
:=
vcl
.
ACLAddress
{
Addr
:
addr
.
Address
,
Negate
:
addr
.
Negate
,
}
if
addr
.
MaskBits
==
nil
{
vclAddr
.
MaskBits
=
vcl
.
NoMaskBits
}
else
{
vclAddr
.
MaskBits
=
uint8
(
*
addr
.
MaskBits
)
}
vclACL
.
Addresses
=
append
(
vclACL
.
Addresses
,
vclAddr
)
}
for
_
,
cond
:=
range
acl
.
Conditions
{
vclMatch
:=
vcl
.
MatchTerm
{
Comparand
:
cond
.
Comparand
,
Regex
:
cond
.
Regex
,
Match
:
cond
.
Match
,
}
vclACL
.
Conditions
=
append
(
vclACL
.
Conditions
,
vclMatch
)
}
worker
.
log
.
Debugf
(
"VarnishConfig %s/%s add VCL ACL config: "
+
"%+v"
,
vcfg
.
Namespace
,
vcfg
.
Name
,
vclACL
)
spec
.
ACLs
=
append
(
spec
.
ACLs
,
vclACL
)
}
return
nil
}
func
(
worker
*
NamespaceWorker
)
hasIngress
(
svc
*
api_v1
.
Service
,
ing
*
extensions
.
Ingress
,
spec
vcl
.
Spec
)
bool
{
...
...
@@ -367,6 +426,9 @@ func (worker *NamespaceWorker) addOrUpdateIng(ing *extensions.Ingress) error {
if
err
=
worker
.
configAuth
(
&
vclSpec
,
vcfg
);
err
!=
nil
{
return
err
}
if
err
=
worker
.
configACL
(
&
vclSpec
,
vcfg
);
err
!=
nil
{
return
err
}
}
else
{
worker
.
log
.
Infof
(
"Found no VarnishConfigs for Varnish Service "
+
"%s/%s"
,
svc
.
Namespace
,
svc
.
Name
)
...
...
pkg/varnish/vcl/acl.tmpl
0 → 100644
View file @
04e83f7f
import std;
{{- range .ACLs}}
acl {{aclName .Name}} {
{{- range .Addresses}}
{{if .Negate}}! {{end}}"{{.Addr}}"{{aclMask .MaskBits}};
{{- end}}
}
{{- end}}
sub vcl_recv {
{{- if hasXFF .ACLs}}
std.collect(req.http.X-Forwarded-For);
{{- end}}
{{- range .ACLs}}
if (
{{- range $cond := .Conditions}}
{{$cond.Comparand}} {{if not .Match}}!{{end}}~ "{{.Regex}}" &&
{{- end}}
{{aclCmp .Comparand}} {{if .Whitelist}}!{{end}}~ {{aclName .Name}}
) {
return(synth({{.FailStatus}}));
}
{{- end}}
}
pkg/varnish/vcl/testdata/acl.golden
0 → 100644
View file @
04e83f7f
import std;
acl vk8s_man_vcl_example_acl {
"localhost";
"192.0.2.0"/24;
! "192.0.2.23";
}
acl vk8s_wikipedia_example_acl {
"192.168.100.14"/24;
"192.168.100.0"/22;
"2001:db8::"/48;
}
acl vk8s_private4_acl {
"10.0.0.0"/24;
"172.16.0.0"/12;
"192.168.0.0"/16;
}
acl vk8s_rfc5737_acl {
"192.0.2.0"/24;
"198.51.100.0"/24;
"203.0.113.0"/24;
}
acl vk8s_local_acl {
"127.0.0.0"/8;
"::1";
}
sub vcl_recv {
std.collect(req.http.X-Forwarded-For);
if (
req.http.Host ~ "^cafe\.example\.com$" &&
req.url ~ "^/coffee(/|$)" &&
client.ip !~ vk8s_man_vcl_example_acl
) {
return(synth(403));
}
if (
req.url !~ "^/tea(/|$)" &&
server.ip ~ vk8s_wikipedia_example_acl
) {
return(synth(404));
}
if (
std.ip(req.http.X-Real-IP, "0.0.0.0") !~ vk8s_private4_acl
) {
return(synth(403));
}
if (
std.ip(regsub(req.http.X-Forwarded-For,"^([^,\s]+).*","\1"), "0.0.0.0") !~ vk8s_rfc5737_acl
) {
return(synth(403));
}
if (
std.ip(regsub(req.http.X-Forwarded-For,"^.*?([\d.]+)\s*,[^,]*$","\1"), "0.0.0.0") !~ vk8s_local_acl
) {
return(synth(403));
}
}
pkg/varnish/vcl/vcl.go
View file @
04e83f7f
...
...
@@ -42,6 +42,7 @@ import (
"path"
"regexp"
"sort"
"strings"
"text/template"
)
...
...
@@ -213,6 +214,91 @@ func (a byRealm) Len() int { return len(a) }
func
(
a
byRealm
)
Swap
(
i
,
j
int
)
{
a
[
i
],
a
[
j
]
=
a
[
j
],
a
[
i
]
}
func
(
a
byRealm
)
Less
(
i
,
j
int
)
bool
{
return
a
[
i
]
.
Realm
<
a
[
j
]
.
Realm
}
// NoMaskBits is a sentinel value for ACLAddress.MaskBits indicating
// that a CIDR range is not to be used.
const
NoMaskBits
uint8
=
255
// ACLAddress represents an element in an ACL -- a host name to be
// resolved at VCL load, an IP address, or address range in CIDR
// notation. Use the '!' for negation when Negate is true.
type
ACLAddress
struct
{
Addr
string
MaskBits
uint8
Negate
bool
}
func
(
addr
ACLAddress
)
hash
(
hash
hash
.
Hash
)
{
hash
.
Write
([]
byte
(
addr
.
Addr
))
hash
.
Write
([]
byte
{
byte
(
addr
.
MaskBits
)})
if
addr
.
Negate
{
hash
.
Write
([]
byte
(
"Negate"
))
}
}
// interface for sorting []ACLAddress
type
byACLAddr
[]
ACLAddress
func
(
a
byACLAddr
)
Len
()
int
{
return
len
(
a
)
}
func
(
a
byACLAddr
)
Swap
(
i
,
j
int
)
{
a
[
i
],
a
[
j
]
=
a
[
j
],
a
[
i
]
}
func
(
a
byACLAddr
)
Less
(
i
,
j
int
)
bool
{
return
a
[
i
]
.
Addr
<
a
[
j
]
.
Addr
}
// MatchTerm is a term describing the comparison of a VCL object with
// a pattern.
type
MatchTerm
struct
{
Comparand
string
Regex
string
Match
bool
}
func
(
match
MatchTerm
)
hash
(
hash
hash
.
Hash
)
{
hash
.
Write
([]
byte
(
match
.
Comparand
))
hash
.
Write
([]
byte
(
match
.
Regex
))
if
match
.
Match
{
hash
.
Write
([]
byte
(
"Match"
))
}
}
// interface for sorting []MatchTerm
type
byComparand
[]
MatchTerm
func
(
a
byComparand
)
Len
()
int
{
return
len
(
a
)
}
func
(
a
byComparand
)
Swap
(
i
,
j
int
)
{
a
[
i
],
a
[
j
]
=
a
[
j
],
a
[
i
]
}
func
(
a
byComparand
)
Less
(
i
,
j
int
)
bool
{
return
a
[
i
]
.
Comparand
<
a
[
j
]
.
Comparand
}
// ACL represents an Access Control List, derived from a
// VarnishConfig.
type
ACL
struct
{
Name
string
Comparand
string
FailStatus
uint16
Whitelist
bool
Addresses
[]
ACLAddress
Conditions
[]
MatchTerm
}
func
(
acl
ACL
)
hash
(
hash
hash
.
Hash
)
{
hash
.
Write
([]
byte
(
acl
.
Name
))
hash
.
Write
([]
byte
(
acl
.
Comparand
))
statusBytes
:=
make
([]
byte
,
2
)
binary
.
BigEndian
.
PutUint16
(
statusBytes
,
uint16
(
acl
.
FailStatus
))
hash
.
Write
(
statusBytes
)
for
_
,
addr
:=
range
acl
.
Addresses
{
addr
.
hash
(
hash
)
}
for
_
,
cond
:=
range
acl
.
Conditions
{
cond
.
hash
(
hash
)
}
}
// interface for sorting []ACL
type
byACLName
[]
ACL
func
(
a
byACLName
)
Len
()
int
{
return
len
(
a
)
}
func
(
a
byACLName
)
Swap
(
i
,
j
int
)
{
a
[
i
],
a
[
j
]
=
a
[
j
],
a
[
i
]
}
func
(
a
byACLName
)
Less
(
i
,
j
int
)
bool
{
return
a
[
i
]
.
Name
<
a
[
j
]
.
Name
}
// Spec is the specification for a VCL configuration derived from
// Ingresses and VarnishConfig Custom Resources. This abstracts the
// VCL to be loaded by all instances of a Varnish Service.
...
...
@@ -234,6 +320,7 @@ type Spec struct {
// Authentication, derived from the Auth section of a
// VarnishConfig.
Auths
[]
Auth
ACLs
[]
ACL
}
// DeepHash computes a 64-bit hash value from a Spec such that if two
...
...
@@ -259,6 +346,9 @@ func (spec Spec) DeepHash() uint64 {
for
_
,
auth
:=
range
spec
.
Auths
{
auth
.
hash
(
hash
)
}
for
_
,
acl
:=
range
spec
.
ACLs
{
acl
.
hash
(
hash
)
}
return
hash
.
Sum64
()
}
...
...
@@ -273,6 +363,7 @@ func (spec Spec) Canonical() Spec {
AllServices
:
make
(
map
[
string
]
Service
,
len
(
spec
.
AllServices
)),
ShardCluster
:
spec
.
ShardCluster
,
Auths
:
make
([]
Auth
,
len
(
spec
.
Auths
)),
ACLs
:
make
([]
ACL
,
len
(
spec
.
ACLs
)),
}
copy
(
canon
.
DefaultService
.
Addresses
,
spec
.
DefaultService
.
Addresses
)
sort
.
Stable
(
byIPPort
(
canon
.
DefaultService
.
Addresses
))
...
...
@@ -296,12 +387,21 @@ func (spec Spec) Canonical() Spec {
for
_
,
auth
:=
range
canon
.
Auths
{
sort
.
Strings
(
auth
.
Credentials
)
}
copy
(
canon
.
ACLs
,
spec
.
ACLs
)
sort
.
Stable
(
byACLName
(
canon
.
ACLs
))
for
_
,
acl
:=
range
canon
.
ACLs
{
sort
.
Stable
(
byACLAddr
(
acl
.
Addresses
))
sort
.
Stable
(
byComparand
(
acl
.
Conditions
))
}
return
canon
}
var
fMap
=
template
.
FuncMap
{
"plusOne"
:
func
(
i
int
)
int
{
return
i
+
1
},
"vclMangle"
:
func
(
s
string
)
string
{
return
mangle
(
s
)
},
"aclMask"
:
func
(
bits
uint8
)
string
{
return
aclMask
(
bits
)
},
"aclCmp"
:
func
(
comparand
string
)
string
{
return
aclCmp
(
comparand
)
},
"hasXFF"
:
func
(
acls
[]
ACL
)
bool
{
return
hasXFF
(
acls
)
},
"backendName"
:
func
(
svc
Service
,
addr
string
)
string
{
return
backendName
(
svc
,
addr
)
},
...
...
@@ -311,18 +411,23 @@ var fMap = template.FuncMap{
"urlMatcher"
:
func
(
rule
Rule
)
string
{
return
urlMatcher
(
rule
)
},
"aclName"
:
func
(
name
string
)
string
{
return
"vk8s_"
+
mangle
(
name
)
+
"_acl"
},
}
const
(
ingTmplSrc
=
"vcl.tmpl"
shardTmplSrc
=
"self-shard.tmpl"
authTmplSrc
=
"auth.tmpl"
aclTmplSrc
=
"acl.tmpl"
)
var
(
ingressTmpl
*
template
.
Template
shardTmpl
*
template
.
Template
authTmpl
*
template
.
Template
aclTmpl
*
template
.
Template
symPattern
=
regexp
.
MustCompile
(
"^[[:alpha:]][[:word:]-]*$"
)
first
=
regexp
.
MustCompile
(
"[[:alpha:]]"
)
restIllegal
=
regexp
.
MustCompile
(
"[^[:word:]-]+"
)
...
...
@@ -334,6 +439,8 @@ func InitTemplates(tmplDir string) error {
ingTmplPath
:=
path
.
Join
(
tmplDir
,
ingTmplSrc
)
shardTmplPath
:=
path
.
Join
(
tmplDir
,
shardTmplSrc
)
authTmplPath
:=
path
.
Join
(
tmplDir
,
authTmplSrc
)
aclTmplPath
:=
path
.
Join
(
tmplDir
,
aclTmplSrc
)
ingressTmpl
,
err
=
template
.
New
(
ingTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
ingTmplPath
)
if
err
!=
nil
{
...
...
@@ -349,6 +456,11 @@ func InitTemplates(tmplDir string) error {
if
err
!=
nil
{
return
err
}
aclTmpl
,
err
=
template
.
New
(
aclTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
aclTmplPath
)
if
err
!=
nil
{
return
err
}
return
nil
}
...
...
@@ -372,6 +484,11 @@ func (spec Spec) GetSrc() (string, error) {
return
""
,
err
}
}
if
len
(
spec
.
ACLs
)
>
0
{
if
err
:=
aclTmpl
.
Execute
(
&
buf
,
spec
);
err
!=
nil
{
return
""
,
err
}
}
if
len
(
spec
.
Auths
)
>
0
{
if
err
:=
authTmpl
.
Execute
(
&
buf
,
spec
);
err
!=
nil
{
return
""
,
err
...
...
@@ -406,3 +523,38 @@ func directorName(svc Service) string {
func
urlMatcher
(
rule
Rule
)
string
{
return
mangle
(
rule
.
Host
+
"_url"
)
}
func
aclMask
(
bits
uint8
)
string
{
if
bits
>
128
{
return
""
}
return
fmt
.
Sprintf
(
"/%d"
,
bits
)
}
const
(
xffFirst
=
`regsub(req.http.X-Forwarded-For,"^([^,\s]+).*","\1")`
xff2ndLast
=
`regsub(req.http.X-Forwarded-For,"^.*?([\d.]+)\s*,[^,]*$","\1")`
)
func
aclCmp
(
comparand
string
)
string
{
if
strings
.
HasPrefix
(
comparand
,
"xff-"
)
||
strings
.
HasPrefix
(
comparand
,
"req.http."
)
{
if
comparand
==
"xff-first"
{
comparand
=
xffFirst
}
else
if
comparand
==
"xff-2ndlast"
{
comparand
=
xff2ndLast
}
return
fmt
.
Sprintf
(
`std.ip(%s, "0.0.0.0")`
,
comparand
)
}
return
comparand
}
func
hasXFF
(
acls
[]
ACL
)
bool
{
for
_
,
acl
:=
range
acls
{
if
strings
.
HasPrefix
(
acl
.
Comparand
,
"xff-"
)
{
return
true
}
}
return
false
}
pkg/varnish/vcl/vcl_test.go
View file @
04e83f7f
...
...
@@ -397,3 +397,167 @@ func TestAuthTemplate(t *testing.T) {
}
}
}
var
acls
=
Spec
{
ACLs
:
[]
ACL
{
{
Name
:
"man_vcl_example"
,
Comparand
:
"client.ip"
,
FailStatus
:
403
,
Whitelist
:
true
,
Addresses
:
[]
ACLAddress
{
ACLAddress
{
Addr
:
"localhost"
,
MaskBits
:
255
,
Negate
:
false
,
},
ACLAddress
{
Addr
:
"192.0.2.0"
,
MaskBits
:
24
,
Negate
:
false
,
},
ACLAddress
{
Addr
:
"192.0.2.23"
,
MaskBits
:
255
,
Negate
:
true
,
},
},
Conditions
:
[]
MatchTerm
{
MatchTerm
{
Comparand
:
"req.http.Host"
,
Match
:
true
,
Regex
:
`^cafe\.example\.com$`
,
},
MatchTerm
{
Comparand
:
"req.url"
,
Match
:
true
,
Regex
:
`^/coffee(/|$)`
,
},
},
},
{
Name
:
"wikipedia_example"
,
Comparand
:
"server.ip"
,
FailStatus
:
404
,
Whitelist
:
false
,
Addresses
:
[]
ACLAddress
{
ACLAddress
{
Addr
:
"192.168.100.14"
,
MaskBits
:
24
,
Negate
:
false
,
},
ACLAddress
{
Addr
:
"192.168.100.0"
,
MaskBits
:
22
,
Negate
:
false
,
},
ACLAddress
{
Addr
:
"2001:db8::"
,
MaskBits
:
48
,
Negate
:
false
,
},
},
Conditions
:
[]
MatchTerm
{
MatchTerm
{
Comparand
:
"req.url"
,
Match
:
false
,
Regex
:
`^/tea(/|$)`
,
},
},
},
{
Name
:
"private4"
,
Comparand
:
"req.http.X-Real-IP"
,
FailStatus
:
403
,
Whitelist
:
true
,
Addresses
:
[]
ACLAddress
{
ACLAddress
{
Addr
:
"10.0.0.0"
,
MaskBits
:
24
,
Negate
:
false
,
},
ACLAddress
{
Addr
:
"172.16.0.0"
,
MaskBits
:
12
,
Negate
:
false
,
},
ACLAddress
{
Addr
:
"192.168.0.0"
,
MaskBits
:
16
,
Negate
:
false
,
},
},
Conditions
:
[]
MatchTerm
{},
},
{
Name
:
"rfc5737"
,
Comparand
:
"xff-first"
,
FailStatus
:
403
,
Whitelist
:
true
,
Addresses
:
[]
ACLAddress
{
ACLAddress
{
Addr
:
"192.0.2.0"
,
MaskBits
:
24
,
Negate
:
false
,
},
ACLAddress
{
Addr
:
"198.51.100.0"
,
MaskBits
:
24
,
Negate
:
false
,
},
ACLAddress
{
Addr
:
"203.0.113.0"
,
MaskBits
:
24
,
Negate
:
false
,
},
},
Conditions
:
[]
MatchTerm
{},
},
{
Name
:
"local"
,
Comparand
:
"xff-2ndlast"
,
FailStatus
:
403
,
Whitelist
:
true
,
Addresses
:
[]
ACLAddress
{
ACLAddress
{
Addr
:
"127.0.0.0"
,
MaskBits
:
8
,
Negate
:
false
,
},
ACLAddress
{
Addr
:
"::1"
,
MaskBits
:
255
,
Negate
:
false
,
},
},
Conditions
:
[]
MatchTerm
{},
},
},
}
func
TestAclTemplate
(
t
*
testing
.
T
)
{
var
buf
bytes
.
Buffer
gold
:=
"acl.golden"
tmplName
:=
"acl.tmpl"
tmpl
,
err
:=
template
.
New
(
tmplName
)
.
Funcs
(
fMap
)
.
ParseFiles
(
tmplName
)
if
err
!=
nil
{
t
.
Error
(
"Cannot parse acl template:"
,
err
)
return
}
if
err
:=
tmpl
.
Execute
(
&
buf
,
acls
);
err
!=
nil
{
t
.
Error
(
"acls template Execute():"
,
err
)
return
}
ok
,
err
:=
cmpGold
(
buf
.
Bytes
(),
gold
)
if
err
!=
nil
{
t
.
Fatalf
(
"Reading %s: %v"
,
gold
,
err
)
}
if
!
ok
{
t
.
Errorf
(
"Generated VCL for authorization does not match gold "
+
"file: %s"
,
gold
)
if
testing
.
Verbose
()
{
t
.
Logf
(
"Generated: %s"
,
buf
.
String
())
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment