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 access control to varnish #7700

Merged
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
320 changes: 188 additions & 132 deletions lib/go-atscfg/ipallowdotyaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/

import (
"errors"
"net"
"sort"
"strconv"
Expand Down Expand Up @@ -73,62 +74,20 @@
return Cfg{}, makeErr(warnings, "this server missing HostName")
}

params := paramsToMultiMap(filterParams(serverParams, IPAllowConfigFileName, "", "", ""))

ipAllowDat := []ipAllowYAMLData{}

// localhost is trusted.
ipAllowDat = append([]ipAllowYAMLData{yamlAllowAll(`127.0.0.1`)}, ipAllowDat...)
ipAllowDat = append([]ipAllowYAMLData{yamlAllowAll(`::1`)}, ipAllowDat...)

// default for coalesce_ipv4 = 24, 5 and for ipv6 48, 5; override with the parameters in the server profile.
coalesceMaskLenV4 := DefaultCoalesceMaskLenV4
coalesceNumberV4 := DefaultCoalesceNumberV4
coalesceMaskLenV6 := DefaultCoalesceMaskLenV6
coalesceNumberV6 := DefaultCoalesceNumberV6
ips := GetPurgeIPs(serverParams)

for name, vals := range params {
for _, val := range vals {
switch name {
case ParamPurgeAllowIP:
for _, ip := range strings.Split(val, ",") {
ipAllowDat = append(ipAllowDat, yamlAllowAll(strings.TrimSpace(ip)))
}
case ParamCoalesceMaskLenV4:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceMaskLenV4 != DefaultCoalesceMaskLenV4 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceMaskLenV4 = vi
}
case ParamCoalesceNumberV4:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceNumberV4 != DefaultCoalesceNumberV4 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceNumberV4 = vi
}
case ParamCoalesceMaskLenV6:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceMaskLenV6 != DefaultCoalesceMaskLenV6 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceMaskLenV6 = vi
}
case ParamCoalesceNumberV6:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")
} else if coalesceNumberV6 != DefaultCoalesceNumberV6 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")
} else {
coalesceNumberV6 = vi
}
}
}
for _, ip := range ips {
ipAllowDat = append(ipAllowDat, yamlAllowAll(strings.TrimSpace(ip)))
}
coalesceMaskLenV4, coalesceNumberV4, coalesceMaskLenV6, coalesceNumberV6, ws := GetCoalesceMaskAndNumber(serverParams)

warnings = append(warnings, ws...)

// for edges deny "PUSH|PURGE|DELETE", allow everything else to everyone.
isMid := strings.HasPrefix(server.Type, tc.MidTypePrefix)
Expand All @@ -137,92 +96,22 @@
ipAllowDat = append(ipAllowDat, yamlAllowAllButPushPurgeDelete(`::/0`))
} else {

ips := []*net.IPNet{}
ip6s := []*net.IPNet{}

cgMap := map[string]tc.CacheGroupNullable{}
for _, cg := range cacheGroups {
if cg.Name == nil {
return Cfg{}, makeErr(warnings, "got cachegroup with nil name!")
}
cgMap[*cg.Name] = cg
}

if server.Cachegroup == nil {
return Cfg{}, makeErr(warnings, "server had nil Cachegroup!")
}

serverCG, ok := cgMap[*server.Cachegroup]
if !ok {
return Cfg{}, makeErr(warnings, "server cachegroup not in cachegroups!")
}

childCGNames := getTopologyDirectChildren(tc.CacheGroupName(*server.Cachegroup), topologies)

childCGs := map[string]tc.CacheGroupNullable{}
for cgName, _ := range childCGNames {
childCGs[string(cgName)] = cgMap[string(cgName)]
}

for cgName, cg := range cgMap {
if (cg.ParentName != nil && *cg.ParentName == *serverCG.Name) || (cg.SecondaryParentName != nil && *cg.SecondaryParentName == *serverCG.Name) {
childCGs[cgName] = cg
}
}

// sort servers, to guarantee things like IP coalescing are deterministic
sort.Sort(serversSortByName(servers))
for _, childServer := range servers {
if childServer.Cachegroup == nil {
warnings = append(warnings, "Servers had server with nil Cachegroup, skipping!")
continue
} else if childServer.HostName == nil {
warnings = append(warnings, "Servers had server with nil HostName, skipping!")
continue
}

// We need to add IPs to the allow of
// - all children of this server
// - all monitors, if this server is a Mid
//
_, isChild := childCGs[*childServer.Cachegroup]
if !isChild && !strings.HasPrefix(server.Type, tc.MidTypePrefix) && string(childServer.Type) != tc.MonitorTypeName {
continue
}

for _, svInterface := range childServer.Interfaces {
for _, svAddr := range svInterface.IPAddresses {
if ip := net.ParseIP(svAddr.Address); ip != nil {
// got an IP - convert it to a CIDR and add it to the list
if ip4 := ip.To4(); ip4 != nil {
ips = append(ips, util.IPToCIDR(ip4))
} else {
ip6s = append(ip6s, util.IPToCIDR(ip))
}
} else {
// not an IP, try a CIDR
if ip, cidr, err := net.ParseCIDR(svAddr.Address); err != nil {
// not a CIDR or IP - error out
warnings = append(warnings, "server '"+*server.HostName+"' IP '"+svAddr.Address+" is not an IP address or CIDR - skipping!")
} else if ip == nil {
// not a CIDR or IP - error out
warnings = append(warnings, "server '"+*server.HostName+"' IP '"+svAddr.Address+" failed to parse as IP or CIDR - skipping!")
} else {
// got a valid CIDR - add it to the list
if ip4 := ip.To4(); ip4 != nil {
ips = append(ips, cidr)
} else {
ip6s = append(ip6s, cidr)
}
}
}
}
}
cidrs, cidr6s, ws, err := GetAllowedCIDRsForMid(
server,
servers,
cacheGroups,
topologies,
coalesceNumberV4,
coalesceMaskLenV4,
coalesceNumberV6,
coalesceMaskLenV6,
)
warnings = append(warnings, ws...)

if err != nil {
return Cfg{}, makeErr(warnings, err.Error())

Check warning on line 112 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L112

Added line #L112 was not covered by tests
}

cidrs := util.CoalesceCIDRs(ips, coalesceNumberV4, coalesceMaskLenV4)
cidr6s := util.CoalesceCIDRs(ip6s, coalesceNumberV6, coalesceMaskLenV6)

for _, cidr := range cidrs {
ipAllowDat = append(ipAllowDat, yamlAllowAllButPushPurge(cidr.String()))
}
Expand Down Expand Up @@ -350,3 +239,170 @@
Methods: []string{YAMLMethodAll},
}
}

// GetPurgeIPs returns IPs allowed for PURGE requests.
func GetPurgeIPs(serverParams []tc.Parameter) []string {
ips := make([]string, 0)

params := paramsToMultiMap(filterParams(serverParams, IPAllowConfigFileName, "", "", ""))

for _, val := range params[ParamPurgeAllowIP] {
ips = append(ips, strings.Split(val, ",")...)
}
return ips
}

// GetCoalesceMaskAndNumber returns coalesce mask length and number for ipv4 and ipv6.
func GetCoalesceMaskAndNumber(serverParams []tc.Parameter) (int, int, int, int, []string) {
warnings := make([]string, 0)

// default for coalesce_ipv4 = 24, 5 and for ipv6 48, 5; override with the parameters in the server profile.
coalesceMaskLenV4 := DefaultCoalesceMaskLenV4
coalesceNumberV4 := DefaultCoalesceNumberV4
coalesceMaskLenV6 := DefaultCoalesceMaskLenV6
coalesceNumberV6 := DefaultCoalesceNumberV6

params := paramsToMultiMap(filterParams(serverParams, IPAllowConfigFileName, "", "", ""))

for name, vals := range params {
for _, val := range vals {
switch name {
case ParamCoalesceMaskLenV4:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")

Check warning on line 272 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L272

Added line #L272 was not covered by tests
} else if coalesceMaskLenV4 != DefaultCoalesceMaskLenV4 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")

Check warning on line 274 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L274

Added line #L274 was not covered by tests
} else {
coalesceMaskLenV4 = vi
}
case ParamCoalesceNumberV4:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")

Check warning on line 280 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L280

Added line #L280 was not covered by tests
} else if coalesceNumberV4 != DefaultCoalesceNumberV4 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")

Check warning on line 282 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L282

Added line #L282 was not covered by tests
} else {
coalesceNumberV4 = vi
}
case ParamCoalesceMaskLenV6:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")

Check warning on line 288 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L288

Added line #L288 was not covered by tests
} else if coalesceMaskLenV6 != DefaultCoalesceMaskLenV6 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")

Check warning on line 290 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L290

Added line #L290 was not covered by tests
} else {
coalesceMaskLenV6 = vi
}
case ParamCoalesceNumberV6:
if vi, err := strconv.Atoi(val); err != nil {
warnings = append(warnings, "got param '"+name+"' val '"+val+"' not a number, ignoring!")

Check warning on line 296 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L296

Added line #L296 was not covered by tests
} else if coalesceNumberV6 != DefaultCoalesceNumberV6 {
warnings = append(warnings, "got multiple param '"+name+"' - ignoring val '"+val+"'!")

Check warning on line 298 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L298

Added line #L298 was not covered by tests
} else {
coalesceNumberV6 = vi
}
}
}
}
return coalesceMaskLenV4, coalesceNumberV4, coalesceMaskLenV6, coalesceNumberV6, nil
}

// GetAllowedCIDRsForMid returns CIDRs allowed for all methods other than Push and Purge to mid servers.
func GetAllowedCIDRsForMid(
server *Server,
servers []Server,
cacheGroups []tc.CacheGroupNullable,
topologies []tc.Topology,
coalesceNumberV4 int,
coalesceMaskLenV4 int,
coalesceNumberV6 int,
coalesceMaskLenV6 int,
) ([]*net.IPNet, []*net.IPNet, []string, error) {

ips := []*net.IPNet{}
ip6s := []*net.IPNet{}
warnings := make([]string, 0)

cgMap := map[string]tc.CacheGroupNullable{}
for _, cg := range cacheGroups {
if cg.Name == nil {
return nil, nil, warnings, errors.New("got cachegroup with nil name!")
}

Check warning on line 328 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L327-L328

Added lines #L327 - L328 were not covered by tests
cgMap[*cg.Name] = cg
}

if server.Cachegroup == nil {
return nil, nil, warnings, errors.New("server had nil Cachegroup!")
}

Check warning on line 334 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L333-L334

Added lines #L333 - L334 were not covered by tests

serverCG, ok := cgMap[*server.Cachegroup]
if !ok {
return nil, nil, warnings, errors.New("server cachegroup not in cachegroups!")
}

Check warning on line 339 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L338-L339

Added lines #L338 - L339 were not covered by tests

childCGNames := getTopologyDirectChildren(tc.CacheGroupName(*server.Cachegroup), topologies)

childCGs := map[string]tc.CacheGroupNullable{}
for cgName, _ := range childCGNames {
childCGs[string(cgName)] = cgMap[string(cgName)]
}

for cgName, cg := range cgMap {
if (cg.ParentName != nil && *cg.ParentName == *serverCG.Name) || (cg.SecondaryParentName != nil && *cg.SecondaryParentName == *serverCG.Name) {
childCGs[cgName] = cg
}

Check warning on line 351 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L350-L351

Added lines #L350 - L351 were not covered by tests
}

// sort servers, to guarantee things like IP coalescing are deterministic
sort.Sort(serversSortByName(servers))
for _, childServer := range servers {
if childServer.Cachegroup == nil {
warnings = append(warnings, "Servers had server with nil Cachegroup, skipping!")
continue

Check warning on line 359 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L358-L359

Added lines #L358 - L359 were not covered by tests
} else if childServer.HostName == nil {
warnings = append(warnings, "Servers had server with nil HostName, skipping!")
continue

Check warning on line 362 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L361-L362

Added lines #L361 - L362 were not covered by tests
}

// We need to add IPs to the allow of
// - all children of this server
// - all monitors, if this server is a Mid
//
_, isChild := childCGs[*childServer.Cachegroup]
if !isChild && !strings.HasPrefix(server.Type, tc.MidTypePrefix) && string(childServer.Type) != tc.MonitorTypeName {
continue

Check warning on line 371 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L371

Added line #L371 was not covered by tests
}

for _, svInterface := range childServer.Interfaces {
for _, svAddr := range svInterface.IPAddresses {
if ip := net.ParseIP(svAddr.Address); ip != nil {
// got an IP - convert it to a CIDR and add it to the list
if ip4 := ip.To4(); ip4 != nil {
ips = append(ips, util.IPToCIDR(ip4))
} else {
ip6s = append(ip6s, util.IPToCIDR(ip))
}
} else {
// not an IP, try a CIDR
if ip, cidr, err := net.ParseCIDR(svAddr.Address); err != nil {
// not a CIDR or IP - error out
warnings = append(warnings, "server '"+*server.HostName+"' IP '"+svAddr.Address+" is not an IP address or CIDR - skipping!")

Check warning on line 387 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L386-L387

Added lines #L386 - L387 were not covered by tests
} else if ip == nil {
// not a CIDR or IP - error out
warnings = append(warnings, "server '"+*server.HostName+"' IP '"+svAddr.Address+" failed to parse as IP or CIDR - skipping!")

Check warning on line 390 in lib/go-atscfg/ipallowdotyaml.go

View check run for this annotation

Codecov / codecov/patch

lib/go-atscfg/ipallowdotyaml.go#L389-L390

Added lines #L389 - L390 were not covered by tests
} else {
// got a valid CIDR - add it to the list
if ip4 := ip.To4(); ip4 != nil {
ips = append(ips, cidr)
} else {
ip6s = append(ip6s, cidr)
}
}
}
}
}
}

cidrs := util.CoalesceCIDRs(ips, coalesceNumberV4, coalesceMaskLenV4)
cidr6s := util.CoalesceCIDRs(ip6s, coalesceNumberV6, coalesceMaskLenV6)

return cidrs, cidr6s, warnings, nil
}
Loading
Loading