Commit 429ce5cc authored by Mahmood Ali's avatar Mahmood Ali
Browse files

ran 'go mod vendor'

parent b8623b37
Showing with 1266 additions and 108 deletions
+1266 -108
......@@ -442,7 +442,7 @@ func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownO
}
// canonicalTarName provides a platform-independent and consistent posix-style
//path for files and directories to be archived regardless of the platform.
// path for files and directories to be archived regardless of the platform.
func canonicalTarName(name string, isDir bool) string {
name = CanonicalTarNameForPath(name)
......@@ -495,13 +495,13 @@ func (ta *tarAppender) addTarFile(path, name string) error {
}
}
//check whether the file is overlayfs whiteout
//if yes, skip re-mapping container ID mappings.
// check whether the file is overlayfs whiteout
// if yes, skip re-mapping container ID mappings.
isOverlayWhiteout := fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0
//handle re-mapping container ID mappings back to host ID mappings before
//writing tar headers/files. We skip whiteout files because they were written
//by the kernel and already have proper ownership relative to the host
// handle re-mapping container ID mappings back to host ID mappings before
// writing tar headers/files. We skip whiteout files because they were written
// by the kernel and already have proper ownership relative to the host
if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
fileIDPair, err := getFileUIDGID(fi.Sys())
if err != nil {
......
......@@ -10,6 +10,7 @@ import (
"syscall"
"github.com/containerd/continuity/fs"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
"golang.org/x/sys/unix"
......@@ -152,9 +153,8 @@ func mknodChar0Overlay(cleansedOriginalPath string) error {
return errors.Wrapf(err, "failed to create a dummy lower file %s", lowerDummy)
}
mOpts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower, upper, work)
// docker/pkg/mount.Mount() requires procfs to be mounted. So we use syscall.Mount() directly instead.
if err := syscall.Mount("overlay", merged, "overlay", uintptr(0), mOpts); err != nil {
return errors.Wrapf(err, "failed to mount overlay (%s) on %s", mOpts, merged)
if err := mount.Mount("overlay", merged, "overlay", mOpts); err != nil {
return err
}
mergedDummy := filepath.Join(merged, dummyBase)
if err := os.Remove(mergedDummy); err != nil {
......@@ -237,9 +237,8 @@ func createDirWithOverlayOpaque(tmp string) (string, error) {
return "", errors.Wrapf(err, "failed to create a dummy lower directory %s", lowerDummy)
}
mOpts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower, upper, work)
// docker/pkg/mount.Mount() requires procfs to be mounted. So we use syscall.Mount() directly instead.
if err := syscall.Mount("overlay", merged, "overlay", uintptr(0), mOpts); err != nil {
return "", errors.Wrapf(err, "failed to mount overlay (%s) on %s", mOpts, merged)
if err := mount.Mount("overlay", merged, "overlay", mOpts); err != nil {
return "", err
}
mergedDummy := filepath.Join(merged, dummyBase)
if err := os.Remove(mergedDummy); err != nil {
......
......@@ -31,7 +31,7 @@ func CanonicalTarNameForPath(p string) string {
// chmodTarEntry is used to adjust the file permissions used in tar header based
// on the platform the archival is done.
func chmodTarEntry(perm os.FileMode) os.FileMode {
//perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.)
// perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.)
permPart := perm & os.ModePerm
noPermPart := perm &^ os.ModePerm
// Add the x bit: make everything +x from windows
......
......@@ -18,8 +18,8 @@ func resolveBinary(binname string) (string, error) {
if err != nil {
return "", err
}
//only return no error if the final resolved binary basename
//matches what was searched for
// only return no error if the final resolved binary basename
// matches what was searched for
if filepath.Base(resolvedPath) == binname {
return resolvedPath, nil
}
......
......@@ -6,9 +6,9 @@ import (
"time"
)
//setCTime will set the create time on a file. On Unix, the create
//time is updated as a side effect of setting the modified time, so
//no action is required.
// setCTime will set the create time on a file. On Unix, the create
// time is updated as a side effect of setting the modified time, so
// no action is required.
func setCTime(path string, ctime time.Time) error {
return nil
}
......@@ -6,8 +6,8 @@ import (
"golang.org/x/sys/windows"
)
//setCTime will set the create time on a file. On Windows, this requires
//calling SetFileTime and explicitly including the create time.
// setCTime will set the create time on a file. On Windows, this requires
// calling SetFileTime and explicitly including the create time.
func setCTime(path string, ctime time.Time) error {
ctimespec := windows.NsecToTimespec(ctime.UnixNano())
pathp, e := windows.UTF16PtrFromString(path)
......
......@@ -130,12 +130,10 @@ func mkdirWithACL(name string, sddl string) error {
// by the daemon. This SHOULD be treated as absolute from a docker processing
// perspective.
func IsAbs(path string) bool {
if !filepath.IsAbs(path) {
if !strings.HasPrefix(path, string(os.PathSeparator)) {
return false
}
if filepath.IsAbs(path) || strings.HasPrefix(path, string(os.PathSeparator)) {
return true
}
return true
return false
}
// The origin of the functions below here are the golang OS and windows packages,
......@@ -235,7 +233,7 @@ func windowsOpenSequential(path string, mode int, _ uint32) (fd windows.Handle,
createmode = windows.OPEN_EXISTING
}
// Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang.
//https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN
h, e := windows.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0)
return h, e
......
package system // import "github.com/docker/docker/pkg/system"
import "syscall"
import "golang.org/x/sys/windows"
// GetLongPathName converts Windows short pathnames to full pathnames.
// For example C:\Users\ADMIN~1 --> C:\Users\Administrator.
// It is a no-op on non-Windows platforms
func GetLongPathName(path string) (string, error) {
// See https://groups.google.com/forum/#!topic/golang-dev/1tufzkruoTg
p := syscall.StringToUTF16(path)
p, err := windows.UTF16FromString(path)
if err != nil {
return "", err
}
b := p // GetLongPathName says we can reuse buffer
n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
n, err := windows.GetLongPathName(&p[0], &b[0], uint32(len(b)))
if err != nil {
return "", err
}
if n > uint32(len(b)) {
b = make([]uint16, n)
_, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
_, err = windows.GetLongPathName(&p[0], &b[0], uint32(len(b)))
if err != nil {
return "", err
}
}
return syscall.UTF16ToString(b), nil
return windows.UTF16ToString(b), nil
}
......@@ -13,6 +13,6 @@ func IsProcessAlive(pid int) bool {
func KillProcess(pid int) {
p, err := os.FindProcess(pid)
if err == nil {
p.Kill()
_ = p.Kill()
}
}
......@@ -63,12 +63,8 @@ func EnsureRemoveAll(dir string) error {
return err
}
if mounted, _ := mount.Mounted(pe.Path); mounted {
if e := mount.Unmount(pe.Path); e != nil {
if mounted, _ := mount.Mounted(pe.Path); mounted {
return errors.Wrapf(e, "error while removing %s", dir)
}
}
if e := mount.Unmount(pe.Path); e != nil {
return errors.Wrapf(e, "error while removing %s", dir)
}
if exitOnErr[pe.Path] == maxRetry {
......
......@@ -9,9 +9,3 @@ import "golang.org/x/sys/unix"
func Unmount(dest string) error {
return unix.Unmount(dest, 0)
}
// CommandLineToArgv should not be used on Unix.
// It simply returns commandLine in the only element in the returned array.
func CommandLineToArgv(commandLine string) ([]string, error) {
return []string{commandLine}, nil
}
package system // import "github.com/docker/docker/pkg/system"
import (
"fmt"
"syscall"
"unsafe"
......@@ -11,36 +10,36 @@ import (
)
const (
OWNER_SECURITY_INFORMATION = 0x00000001
GROUP_SECURITY_INFORMATION = 0x00000002
DACL_SECURITY_INFORMATION = 0x00000004
SACL_SECURITY_INFORMATION = 0x00000008
LABEL_SECURITY_INFORMATION = 0x00000010
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
SCOPE_SECURITY_INFORMATION = 0x00000040
OWNER_SECURITY_INFORMATION = windows.OWNER_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.OWNER_SECURITY_INFORMATION
GROUP_SECURITY_INFORMATION = windows.GROUP_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.GROUP_SECURITY_INFORMATION
DACL_SECURITY_INFORMATION = windows.DACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.DACL_SECURITY_INFORMATION
SACL_SECURITY_INFORMATION = windows.SACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.SACL_SECURITY_INFORMATION
LABEL_SECURITY_INFORMATION = windows.LABEL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.LABEL_SECURITY_INFORMATION
ATTRIBUTE_SECURITY_INFORMATION = windows.ATTRIBUTE_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.ATTRIBUTE_SECURITY_INFORMATION
SCOPE_SECURITY_INFORMATION = windows.SCOPE_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.SCOPE_SECURITY_INFORMATION
PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080
ACCESS_FILTER_SECURITY_INFORMATION = 0x00000100
BACKUP_SECURITY_INFORMATION = 0x00010000
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
BACKUP_SECURITY_INFORMATION = windows.BACKUP_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.BACKUP_SECURITY_INFORMATION
PROTECTED_DACL_SECURITY_INFORMATION = windows.PROTECTED_DACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.PROTECTED_DACL_SECURITY_INFORMATION
PROTECTED_SACL_SECURITY_INFORMATION = windows.PROTECTED_SACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.PROTECTED_SACL_SECURITY_INFORMATION
UNPROTECTED_DACL_SECURITY_INFORMATION = windows.UNPROTECTED_DACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.UNPROTECTED_DACL_SECURITY_INFORMATION
UNPROTECTED_SACL_SECURITY_INFORMATION = windows.UNPROTECTED_SACL_SECURITY_INFORMATION // Deprecated: use golang.org/x/sys/windows.UNPROTECTED_SACL_SECURITY_INFORMATION
)
const (
SE_UNKNOWN_OBJECT_TYPE = iota
SE_FILE_OBJECT
SE_SERVICE
SE_PRINTER
SE_REGISTRY_KEY
SE_LMSHARE
SE_KERNEL_OBJECT
SE_WINDOW_OBJECT
SE_DS_OBJECT
SE_DS_OBJECT_ALL
SE_PROVIDER_DEFINED_OBJECT
SE_WMIGUID_OBJECT
SE_REGISTRY_WOW64_32KEY
SE_UNKNOWN_OBJECT_TYPE = windows.SE_UNKNOWN_OBJECT_TYPE // Deprecated: use golang.org/x/sys/windows.SE_UNKNOWN_OBJECT_TYPE
SE_FILE_OBJECT = windows.SE_FILE_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_FILE_OBJECT
SE_SERVICE = windows.SE_SERVICE // Deprecated: use golang.org/x/sys/windows.SE_SERVICE
SE_PRINTER = windows.SE_PRINTER // Deprecated: use golang.org/x/sys/windows.SE_PRINTER
SE_REGISTRY_KEY = windows.SE_REGISTRY_KEY // Deprecated: use golang.org/x/sys/windows.SE_REGISTRY_KEY
SE_LMSHARE = windows.SE_LMSHARE // Deprecated: use golang.org/x/sys/windows.SE_LMSHARE
SE_KERNEL_OBJECT = windows.SE_KERNEL_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_KERNEL_OBJECT
SE_WINDOW_OBJECT = windows.SE_WINDOW_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_WINDOW_OBJECT
SE_DS_OBJECT = windows.SE_DS_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_DS_OBJECT
SE_DS_OBJECT_ALL = windows.SE_DS_OBJECT_ALL // Deprecated: use golang.org/x/sys/windows.SE_DS_OBJECT_ALL
SE_PROVIDER_DEFINED_OBJECT = windows.SE_PROVIDER_DEFINED_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_PROVIDER_DEFINED_OBJECT
SE_WMIGUID_OBJECT = windows.SE_WMIGUID_OBJECT // Deprecated: use golang.org/x/sys/windows.SE_WMIGUID_OBJECT
SE_REGISTRY_WOW64_32KEY = windows.SE_REGISTRY_WOW64_32KEY // Deprecated: use golang.org/x/sys/windows.SE_REGISTRY_WOW64_32KEY
)
const (
......@@ -62,9 +61,10 @@ var (
// OSVersion is a wrapper for Windows version information
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
type OSVersion osversion.OSVersion
type OSVersion = osversion.OSVersion
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx
// TODO: use golang.org/x/sys/windows.OsVersionInfoEx (needs OSVersionInfoSize to be exported)
type osVersionInfoEx struct {
OSVersionInfoSize uint32
MajorVersion uint32
......@@ -83,16 +83,10 @@ type osVersionInfoEx struct {
// dockerd.exe must be manifested to get the correct version information.
// Deprecated: use github.com/Microsoft/hcsshim/osversion.Get() instead
func GetOSVersion() OSVersion {
return OSVersion(osversion.Get())
}
func (osv OSVersion) ToString() string {
return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build)
return osversion.Get()
}
// IsWindowsClient returns true if the SKU is client
// @engine maintainers - this function should not be removed or modified as it
// is used to enforce licensing restrictions on Windows.
func IsWindowsClient() bool {
osviex := &osVersionInfoEx{OSVersionInfoSize: 284}
r1, _, err := procGetVersionExW.Call(uintptr(unsafe.Pointer(osviex)))
......@@ -106,33 +100,10 @@ func IsWindowsClient() bool {
// Unmount is a platform-specific helper function to call
// the unmount syscall. Not supported on Windows
func Unmount(dest string) error {
func Unmount(_ string) error {
return nil
}
// CommandLineToArgv wraps the Windows syscall to turn a commandline into an argument array.
func CommandLineToArgv(commandLine string) ([]string, error) {
var argc int32
argsPtr, err := windows.UTF16PtrFromString(commandLine)
if err != nil {
return nil, err
}
argv, err := windows.CommandLineToArgv(argsPtr, &argc)
if err != nil {
return nil, err
}
defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(argv))))
newArgs := make([]string, argc)
for i, v := range (*argv)[:argc] {
newArgs[i] = string(windows.UTF16ToString((*v)[:]))
}
return newArgs, nil
}
// HasWin32KSupport determines whether containers that depend on win32k can
// run on this machine. Win32k is the driver used to implement windowing.
func HasWin32KSupport() bool {
......@@ -154,7 +125,7 @@ func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, da
r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(securityDescriptor)), uintptr(unsafe.Pointer(daclPresent)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclDefaulted)), 0, 0)
if r1 == 0 {
if e1 != 0 {
result = syscall.Errno(e1)
result = e1
} else {
result = syscall.EINVAL
}
......
......@@ -6,16 +6,24 @@ import "golang.org/x/sys/unix"
// and associated with the given path in the file system.
// It will returns a nil slice and nil error if the xattr is not set.
func Lgetxattr(path string, attr string) ([]byte, error) {
// Start with a 128 length byte array
dest := make([]byte, 128)
sz, errno := unix.Lgetxattr(path, attr, dest)
if errno == unix.ENODATA {
return nil, nil
}
if errno == unix.ERANGE {
for errno == unix.ERANGE {
// Buffer too small, use zero-sized buffer to get the actual size
sz, errno = unix.Lgetxattr(path, attr, []byte{})
if errno != nil {
return nil, errno
}
dest = make([]byte, sz)
sz, errno = unix.Lgetxattr(path, attr, dest)
}
if errno != nil {
switch {
case errno == unix.ENODATA:
return nil, nil
case errno != nil:
return nil, errno
}
......
package acl
const (
WildcardName = "*"
)
// Config encapsualtes all of the generic configuration parameters used for
// policy parsing and enforcement
type Config struct {
// WildcardName is the string that represents a request to authorize a wildcard permission
WildcardName string
// embedded enterprise configuration
EnterpriseConfig
}
// GetWildcardName will retrieve the configured wildcard name or provide a default
// in the case that the config is Nil or the wildcard name is unset.
func (c *Config) GetWildcardName() string {
if c == nil || c.WildcardName == "" {
return WildcardName
}
return c.WildcardName
}
// Close will relinquish any resources this Config might be holding on to or
// managing.
func (c *Config) Close() {
if c != nil {
c.EnterpriseConfig.Close()
}
}
// +build !consulent
package acl
type EnterpriseConfig struct {
// no fields in OSS
}
func (_ *EnterpriseConfig) Close() {
// do nothing
}
package acl
import (
"fmt"
"strings"
)
type EnforcementDecision int
const (
// Deny returned from an Authorizer enforcement method indicates
// that a corresponding rule was found and that access should be denied
Deny EnforcementDecision = iota
// Allow returned from an Authorizer enforcement method indicates
// that a corresponding rule was found and that access should be allowed
Allow
// Default returned from an Authorizer enforcement method indicates
// that a corresponding rule was not found and that whether access
// should be granted or denied should be deferred to the default
// access level
Default
)
func (d EnforcementDecision) String() string {
switch d {
case Allow:
return "Allow"
case Deny:
return "Deny"
case Default:
return "Default"
default:
return "Unknown"
}
}
type Resource string
const (
ResourceACL Resource = "acl"
ResourceAgent Resource = "agent"
ResourceEvent Resource = "event"
ResourceIntention Resource = "intention"
ResourceKey Resource = "key"
ResourceKeyring Resource = "keyring"
ResourceNode Resource = "node"
ResourceOperator Resource = "operator"
ResourceQuery Resource = "query"
ResourceService Resource = "service"
ResourceSession Resource = "session"
)
// Authorizer is the interface for policy enforcement.
type Authorizer interface {
// ACLRead checks for permission to list all the ACLs
ACLRead(*AuthorizerContext) EnforcementDecision
// ACLWrite checks for permission to manipulate ACLs
ACLWrite(*AuthorizerContext) EnforcementDecision
// AgentRead checks for permission to read from agent endpoints for a
// given node.
AgentRead(string, *AuthorizerContext) EnforcementDecision
// AgentWrite checks for permission to make changes via agent endpoints
// for a given node.
AgentWrite(string, *AuthorizerContext) EnforcementDecision
// EventRead determines if a specific event can be queried.
EventRead(string, *AuthorizerContext) EnforcementDecision
// EventWrite determines if a specific event may be fired.
EventWrite(string, *AuthorizerContext) EnforcementDecision
// IntentionDefaultAllow determines the default authorized behavior
// when no intentions match a Connect request.
IntentionDefaultAllow(*AuthorizerContext) EnforcementDecision
// IntentionRead determines if a specific intention can be read.
IntentionRead(string, *AuthorizerContext) EnforcementDecision
// IntentionWrite determines if a specific intention can be
// created, modified, or deleted.
IntentionWrite(string, *AuthorizerContext) EnforcementDecision
// KeyList checks for permission to list keys under a prefix
KeyList(string, *AuthorizerContext) EnforcementDecision
// KeyRead checks for permission to read a given key
KeyRead(string, *AuthorizerContext) EnforcementDecision
// KeyWrite checks for permission to write a given key
KeyWrite(string, *AuthorizerContext) EnforcementDecision
// KeyWritePrefix checks for permission to write to an
// entire key prefix. This means there must be no sub-policies
// that deny a write.
KeyWritePrefix(string, *AuthorizerContext) EnforcementDecision
// KeyringRead determines if the encryption keyring used in
// the gossip layer can be read.
KeyringRead(*AuthorizerContext) EnforcementDecision
// KeyringWrite determines if the keyring can be manipulated
KeyringWrite(*AuthorizerContext) EnforcementDecision
// NodeRead checks for permission to read (discover) a given node.
NodeRead(string, *AuthorizerContext) EnforcementDecision
// NodeWrite checks for permission to create or update (register) a
// given node.
NodeWrite(string, *AuthorizerContext) EnforcementDecision
// OperatorRead determines if the read-only Consul operator functions
// can be used.
OperatorRead(*AuthorizerContext) EnforcementDecision
// OperatorWrite determines if the state-changing Consul operator
// functions can be used.
OperatorWrite(*AuthorizerContext) EnforcementDecision
// PreparedQueryRead determines if a specific prepared query can be read
// to show its contents (this is not used for execution).
PreparedQueryRead(string, *AuthorizerContext) EnforcementDecision
// PreparedQueryWrite determines if a specific prepared query can be
// created, modified, or deleted.
PreparedQueryWrite(string, *AuthorizerContext) EnforcementDecision
// ServiceRead checks for permission to read a given service
ServiceRead(string, *AuthorizerContext) EnforcementDecision
// ServiceWrite checks for permission to create or update a given
// service
ServiceWrite(string, *AuthorizerContext) EnforcementDecision
// SessionRead checks for permission to read sessions for a given node.
SessionRead(string, *AuthorizerContext) EnforcementDecision
// SessionWrite checks for permission to create sessions for a given
// node.
SessionWrite(string, *AuthorizerContext) EnforcementDecision
// Snapshot checks for permission to take and restore snapshots.
Snapshot(*AuthorizerContext) EnforcementDecision
// Embedded Interface for Consul Enterprise specific ACL enforcement
enterpriseAuthorizer
}
func Enforce(authz Authorizer, rsc Resource, segment string, access string, ctx *AuthorizerContext) (EnforcementDecision, error) {
lowerAccess := strings.ToLower(access)
switch rsc {
case ResourceACL:
switch lowerAccess {
case "read":
return authz.ACLRead(ctx), nil
case "write":
return authz.ACLWrite(ctx), nil
}
case ResourceAgent:
switch lowerAccess {
case "read":
return authz.AgentRead(segment, ctx), nil
case "write":
return authz.AgentWrite(segment, ctx), nil
}
case ResourceEvent:
switch lowerAccess {
case "read":
return authz.EventRead(segment, ctx), nil
case "write":
return authz.EventWrite(segment, ctx), nil
}
case ResourceIntention:
switch lowerAccess {
case "read":
return authz.IntentionRead(segment, ctx), nil
case "write":
return authz.IntentionWrite(segment, ctx), nil
}
case ResourceKey:
switch lowerAccess {
case "read":
return authz.KeyRead(segment, ctx), nil
case "list":
return authz.KeyList(segment, ctx), nil
case "write":
return authz.KeyWrite(segment, ctx), nil
case "write-prefix":
return authz.KeyWritePrefix(segment, ctx), nil
}
case ResourceKeyring:
switch lowerAccess {
case "read":
return authz.KeyringRead(ctx), nil
case "write":
return authz.KeyringWrite(ctx), nil
}
case ResourceNode:
switch lowerAccess {
case "read":
return authz.NodeRead(segment, ctx), nil
case "write":
return authz.NodeWrite(segment, ctx), nil
}
case ResourceOperator:
switch lowerAccess {
case "read":
return authz.OperatorRead(ctx), nil
case "write":
return authz.OperatorWrite(ctx), nil
}
case ResourceQuery:
switch lowerAccess {
case "read":
return authz.PreparedQueryRead(segment, ctx), nil
case "write":
return authz.PreparedQueryWrite(segment, ctx), nil
}
case ResourceService:
switch lowerAccess {
case "read":
return authz.ServiceRead(segment, ctx), nil
case "write":
return authz.ServiceWrite(segment, ctx), nil
}
case ResourceSession:
switch lowerAccess {
case "read":
return authz.SessionRead(segment, ctx), nil
case "write":
return authz.SessionWrite(segment, ctx), nil
}
default:
if processed, decision, err := enforceEnterprise(authz, rsc, segment, lowerAccess, ctx); processed {
return decision, err
}
return Deny, fmt.Errorf("Invalid ACL resource requested: %q", rsc)
}
return Deny, fmt.Errorf("Invalid access level for %s resource: %s", rsc, access)
}
// NewAuthorizerFromRules is a convenience function to invoke NewPolicyFromSource followed by NewPolicyAuthorizer with
// the parse policy.
func NewAuthorizerFromRules(id string, revision uint64, rules string, syntax SyntaxVersion, conf *Config, meta *EnterprisePolicyMeta) (Authorizer, error) {
policy, err := NewPolicyFromSource(id, revision, rules, syntax, conf, meta)
if err != nil {
return nil, err
}
return NewPolicyAuthorizer([]*Policy{policy}, conf)
}
// +build !consulent
package acl
// AuthorizerContext stub
type AuthorizerContext struct{}
// enterpriseAuthorizer stub interface
type enterpriseAuthorizer interface{}
func enforceEnterprise(_ Authorizer, _ Resource, _ string, _ string, _ *AuthorizerContext) (bool, EnforcementDecision, error) {
return false, Deny, nil
}
package acl
// ChainedAuthorizer can combine multiple Authorizers into one.
// Each Authorizer in the chain is asked (in order) for an
// enforcement decision. The first non-Default decision that
// is rendered by an Authorizer in the chain will be used
// as the overall decision of the ChainedAuthorizer
type ChainedAuthorizer struct {
chain []Authorizer
}
// NewChainedAuthorizer creates a ChainedAuthorizer with the provided
// chain of Authorizers. The slice provided should be in the order of
// most precedent Authorizer at the beginning and least precedent
// Authorizer at the end.
func NewChainedAuthorizer(chain []Authorizer) *ChainedAuthorizer {
return &ChainedAuthorizer{
chain: chain,
}
}
func (c *ChainedAuthorizer) AuthorizerChain() []Authorizer {
return c.chain
}
func (c *ChainedAuthorizer) executeChain(enforce func(authz Authorizer) EnforcementDecision) EnforcementDecision {
for _, authz := range c.chain {
decision := enforce(authz)
if decision != Default {
return decision
}
}
return Deny
}
// ACLRead checks for permission to list all the ACLs
func (c *ChainedAuthorizer) ACLRead(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.ACLRead(entCtx)
})
}
// ACLWrite checks for permission to manipulate ACLs
func (c *ChainedAuthorizer) ACLWrite(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.ACLWrite(entCtx)
})
}
// AgentRead checks for permission to read from agent endpoints for a
// given node.
func (c *ChainedAuthorizer) AgentRead(node string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.AgentRead(node, entCtx)
})
}
// AgentWrite checks for permission to make changes via agent endpoints
// for a given node.
func (c *ChainedAuthorizer) AgentWrite(node string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.AgentWrite(node, entCtx)
})
}
// EventRead determines if a specific event can be queried.
func (c *ChainedAuthorizer) EventRead(name string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.EventRead(name, entCtx)
})
}
// EventWrite determines if a specific event may be fired.
func (c *ChainedAuthorizer) EventWrite(name string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.EventWrite(name, entCtx)
})
}
// IntentionDefaultAllow determines the default authorized behavior
// when no intentions match a Connect request.
func (c *ChainedAuthorizer) IntentionDefaultAllow(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.IntentionDefaultAllow(entCtx)
})
}
// IntentionRead determines if a specific intention can be read.
func (c *ChainedAuthorizer) IntentionRead(prefix string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.IntentionRead(prefix, entCtx)
})
}
// IntentionWrite determines if a specific intention can be
// created, modified, or deleted.
func (c *ChainedAuthorizer) IntentionWrite(prefix string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.IntentionWrite(prefix, entCtx)
})
}
// KeyList checks for permission to list keys under a prefix
func (c *ChainedAuthorizer) KeyList(keyPrefix string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.KeyList(keyPrefix, entCtx)
})
}
// KeyRead checks for permission to read a given key
func (c *ChainedAuthorizer) KeyRead(key string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.KeyRead(key, entCtx)
})
}
// KeyWrite checks for permission to write a given key
func (c *ChainedAuthorizer) KeyWrite(key string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.KeyWrite(key, entCtx)
})
}
// KeyWritePrefix checks for permission to write to an
// entire key prefix. This means there must be no sub-policies
// that deny a write.
func (c *ChainedAuthorizer) KeyWritePrefix(keyPrefix string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.KeyWritePrefix(keyPrefix, entCtx)
})
}
// KeyringRead determines if the encryption keyring used in
// the gossip layer can be read.
func (c *ChainedAuthorizer) KeyringRead(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.KeyringRead(entCtx)
})
}
// KeyringWrite determines if the keyring can be manipulated
func (c *ChainedAuthorizer) KeyringWrite(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.KeyringWrite(entCtx)
})
}
// NodeRead checks for permission to read (discover) a given node.
func (c *ChainedAuthorizer) NodeRead(node string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.NodeRead(node, entCtx)
})
}
// NodeWrite checks for permission to create or update (register) a
// given node.
func (c *ChainedAuthorizer) NodeWrite(node string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.NodeWrite(node, entCtx)
})
}
// OperatorRead determines if the read-only Consul operator functions
// can be used.
func (c *ChainedAuthorizer) OperatorRead(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.OperatorRead(entCtx)
})
}
// OperatorWrite determines if the state-changing Consul operator
// functions can be used.
func (c *ChainedAuthorizer) OperatorWrite(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.OperatorWrite(entCtx)
})
}
// PreparedQueryRead determines if a specific prepared query can be read
// to show its contents (this is not used for execution).
func (c *ChainedAuthorizer) PreparedQueryRead(query string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.PreparedQueryRead(query, entCtx)
})
}
// PreparedQueryWrite determines if a specific prepared query can be
// created, modified, or deleted.
func (c *ChainedAuthorizer) PreparedQueryWrite(query string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.PreparedQueryWrite(query, entCtx)
})
}
// ServiceRead checks for permission to read a given service
func (c *ChainedAuthorizer) ServiceRead(name string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.ServiceRead(name, entCtx)
})
}
// ServiceWrite checks for permission to create or update a given
// service
func (c *ChainedAuthorizer) ServiceWrite(name string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.ServiceWrite(name, entCtx)
})
}
// SessionRead checks for permission to read sessions for a given node.
func (c *ChainedAuthorizer) SessionRead(node string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.SessionRead(node, entCtx)
})
}
// SessionWrite checks for permission to create sessions for a given
// node.
func (c *ChainedAuthorizer) SessionWrite(node string, entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.SessionWrite(node, entCtx)
})
}
// Snapshot checks for permission to take and restore snapshots.
func (c *ChainedAuthorizer) Snapshot(entCtx *AuthorizerContext) EnforcementDecision {
return c.executeChain(func(authz Authorizer) EnforcementDecision {
return authz.Snapshot(entCtx)
})
}
package acl
import (
"errors"
"strings"
)
// These error constants define the standard ACL error types. The values
// must not be changed since the error values are sent via RPC calls
// from older clients and may not have the correct type.
const (
errNotFound = "ACL not found"
errRootDenied = "Cannot resolve root ACL"
errDisabled = "ACL support disabled"
errPermissionDenied = "Permission denied"
errInvalidParent = "Invalid Parent"
)
var (
// ErrNotFound indicates there is no matching ACL.
ErrNotFound = errors.New(errNotFound)
// ErrRootDenied is returned when attempting to resolve a root ACL.
ErrRootDenied = errors.New(errRootDenied)
// ErrDisabled is returned when ACL changes are not permitted since
// they are disabled.
ErrDisabled = errors.New(errDisabled)
// ErrPermissionDenied is returned when an ACL based rejection
// happens.
ErrPermissionDenied = PermissionDeniedError{}
// ErrInvalidParent is returned when a remotely resolve ACL
// token claims to have a non-root parent
ErrInvalidParent = errors.New(errInvalidParent)
)
// IsErrNotFound checks if the given error message is comparable to
// ErrNotFound.
func IsErrNotFound(err error) bool {
return err != nil && strings.Contains(err.Error(), errNotFound)
}
// IsErrRootDenied checks if the given error message is comparable to
// ErrRootDenied.
func IsErrRootDenied(err error) bool {
return err != nil && strings.Contains(err.Error(), errRootDenied)
}
// IsErrDisabled checks if the given error message is comparable to
// ErrDisabled.
func IsErrDisabled(err error) bool {
return err != nil && strings.Contains(err.Error(), errDisabled)
}
// IsErrPermissionDenied checks if the given error message is comparable
// to ErrPermissionDenied.
func IsErrPermissionDenied(err error) bool {
return err != nil && strings.Contains(err.Error(), errPermissionDenied)
}
type PermissionDeniedError struct {
Cause string
}
func (e PermissionDeniedError) Error() string {
if e.Cause != "" {
return errPermissionDenied + ": " + e.Cause
}
return errPermissionDenied
}
package acl
import (
"bytes"
"fmt"
"strconv"
"strings"
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/ast"
hclprinter "github.com/hashicorp/hcl/hcl/printer"
"github.com/hashicorp/hcl/hcl/token"
)
type SyntaxVersion int
const (
SyntaxCurrent SyntaxVersion = iota
SyntaxLegacy
)
const (
PolicyDeny = "deny"
PolicyRead = "read"
PolicyList = "list"
PolicyWrite = "write"
)
type AccessLevel int
const (
AccessUnknown AccessLevel = iota
AccessDeny
AccessRead
AccessList
AccessWrite
)
func (l AccessLevel) String() string {
switch l {
case AccessDeny:
return PolicyDeny
case AccessRead:
return PolicyRead
case AccessList:
return PolicyList
case AccessWrite:
return PolicyWrite
default:
return "unknown"
}
}
func AccessLevelFromString(level string) (AccessLevel, error) {
switch strings.ToLower(level) {
case PolicyDeny:
return AccessDeny, nil
case PolicyRead:
return AccessRead, nil
case PolicyList:
return AccessList, nil
case PolicyWrite:
return AccessWrite, nil
default:
return AccessUnknown, fmt.Errorf("%q is not a valid access level", level)
}
}
type PolicyRules struct {
ACL string `hcl:"acl,expand"`
Agents []*AgentRule `hcl:"agent,expand"`
AgentPrefixes []*AgentRule `hcl:"agent_prefix,expand"`
Keys []*KeyRule `hcl:"key,expand"`
KeyPrefixes []*KeyRule `hcl:"key_prefix,expand"`
Nodes []*NodeRule `hcl:"node,expand"`
NodePrefixes []*NodeRule `hcl:"node_prefix,expand"`
Services []*ServiceRule `hcl:"service,expand"`
ServicePrefixes []*ServiceRule `hcl:"service_prefix,expand"`
Sessions []*SessionRule `hcl:"session,expand"`
SessionPrefixes []*SessionRule `hcl:"session_prefix,expand"`
Events []*EventRule `hcl:"event,expand"`
EventPrefixes []*EventRule `hcl:"event_prefix,expand"`
PreparedQueries []*PreparedQueryRule `hcl:"query,expand"`
PreparedQueryPrefixes []*PreparedQueryRule `hcl:"query_prefix,expand"`
Keyring string `hcl:"keyring"`
Operator string `hcl:"operator"`
}
// Policy is used to represent the policy specified by an ACL configuration.
type Policy struct {
ID string `hcl:"id"`
Revision uint64 `hcl:"revision"`
PolicyRules `hcl:",squash"`
EnterprisePolicyRules `hcl:",squash"`
}
// AgentRule represents a rule for working with agent endpoints on nodes
// with specific name prefixes.
type AgentRule struct {
Node string `hcl:",key"`
Policy string
}
// KeyRule represents a rule for a key
type KeyRule struct {
Prefix string `hcl:",key"`
Policy string
EnterpriseRule `hcl:",squash"`
}
// NodeRule represents a rule for a node
type NodeRule struct {
Name string `hcl:",key"`
Policy string
EnterpriseRule `hcl:",squash"`
}
// ServiceRule represents a policy for a service
type ServiceRule struct {
Name string `hcl:",key"`
Policy string
// Intentions is the policy for intentions where this service is the
// destination. This may be empty, in which case the Policy determines
// the intentions policy.
Intentions string
EnterpriseRule `hcl:",squash"`
}
// SessionRule represents a rule for making sessions tied to specific node
// name prefixes.
type SessionRule struct {
Node string `hcl:",key"`
Policy string
}
// EventRule represents a user event rule.
type EventRule struct {
Event string `hcl:",key"`
Policy string
}
// PreparedQueryRule represents a prepared query rule.
type PreparedQueryRule struct {
Prefix string `hcl:",key"`
Policy string
}
// isPolicyValid makes sure the given string matches one of the valid policies.
func isPolicyValid(policy string, allowList bool) bool {
access, err := AccessLevelFromString(policy)
if err != nil {
return false
}
if access == AccessList && !allowList {
return false
}
return true
}
func (pr *PolicyRules) Validate(conf *Config) error {
// Validate the acl policy - this one is allowed to be empty
if pr.ACL != "" && !isPolicyValid(pr.ACL, false) {
return fmt.Errorf("Invalid acl policy: %#v", pr.ACL)
}
// Validate the agent policy
for _, ap := range pr.Agents {
if !isPolicyValid(ap.Policy, false) {
return fmt.Errorf("Invalid agent policy: %#v", ap)
}
}
for _, ap := range pr.AgentPrefixes {
if !isPolicyValid(ap.Policy, false) {
return fmt.Errorf("Invalid agent_prefix policy: %#v", ap)
}
}
// Validate the key policy
for _, kp := range pr.Keys {
if !isPolicyValid(kp.Policy, true) {
return fmt.Errorf("Invalid key policy: %#v", kp)
}
if err := kp.EnterpriseRule.Validate(kp.Policy, conf); err != nil {
return fmt.Errorf("Invalid key enterprise policy: %#v, got error: %v", kp, err)
}
}
for _, kp := range pr.KeyPrefixes {
if !isPolicyValid(kp.Policy, true) {
return fmt.Errorf("Invalid key_prefix policy: %#v", kp)
}
if err := kp.EnterpriseRule.Validate(kp.Policy, conf); err != nil {
return fmt.Errorf("Invalid key_prefix enterprise policy: %#v, got error: %v", kp, err)
}
}
// Validate the node policies
for _, np := range pr.Nodes {
if !isPolicyValid(np.Policy, false) {
return fmt.Errorf("Invalid node policy: %#v", np)
}
if err := np.EnterpriseRule.Validate(np.Policy, conf); err != nil {
return fmt.Errorf("Invalid node enterprise policy: %#v, got error: %v", np, err)
}
}
for _, np := range pr.NodePrefixes {
if !isPolicyValid(np.Policy, false) {
return fmt.Errorf("Invalid node_prefix policy: %#v", np)
}
if err := np.EnterpriseRule.Validate(np.Policy, conf); err != nil {
return fmt.Errorf("Invalid node_prefix enterprise policy: %#v, got error: %v", np, err)
}
}
// Validate the service policies
for _, sp := range pr.Services {
if !isPolicyValid(sp.Policy, false) {
return fmt.Errorf("Invalid service policy: %#v", sp)
}
if sp.Intentions != "" && !isPolicyValid(sp.Intentions, false) {
return fmt.Errorf("Invalid service intentions policy: %#v", sp)
}
if err := sp.EnterpriseRule.Validate(sp.Policy, conf); err != nil {
return fmt.Errorf("Invalid service enterprise policy: %#v, got error: %v", sp, err)
}
}
for _, sp := range pr.ServicePrefixes {
if !isPolicyValid(sp.Policy, false) {
return fmt.Errorf("Invalid service_prefix policy: %#v", sp)
}
if sp.Intentions != "" && !isPolicyValid(sp.Intentions, false) {
return fmt.Errorf("Invalid service_prefix intentions policy: %#v", sp)
}
if err := sp.EnterpriseRule.Validate(sp.Policy, conf); err != nil {
return fmt.Errorf("Invalid service_prefix enterprise policy: %#v, got error: %v", sp, err)
}
}
// Validate the session policies
for _, sp := range pr.Sessions {
if !isPolicyValid(sp.Policy, false) {
return fmt.Errorf("Invalid session policy: %#v", sp)
}
}
for _, sp := range pr.SessionPrefixes {
if !isPolicyValid(sp.Policy, false) {
return fmt.Errorf("Invalid session_prefix policy: %#v", sp)
}
}
// Validate the user event policies
for _, ep := range pr.Events {
if !isPolicyValid(ep.Policy, false) {
return fmt.Errorf("Invalid event policy: %#v", ep)
}
}
for _, ep := range pr.EventPrefixes {
if !isPolicyValid(ep.Policy, false) {
return fmt.Errorf("Invalid event_prefix policy: %#v", ep)
}
}
// Validate the prepared query policies
for _, pq := range pr.PreparedQueries {
if !isPolicyValid(pq.Policy, false) {
return fmt.Errorf("Invalid query policy: %#v", pq)
}
}
for _, pq := range pr.PreparedQueryPrefixes {
if !isPolicyValid(pq.Policy, false) {
return fmt.Errorf("Invalid query_prefix policy: %#v", pq)
}
}
// Validate the keyring policy - this one is allowed to be empty
if pr.Keyring != "" && !isPolicyValid(pr.Keyring, false) {
return fmt.Errorf("Invalid keyring policy: %#v", pr.Keyring)
}
// Validate the operator policy - this one is allowed to be empty
if pr.Operator != "" && !isPolicyValid(pr.Operator, false) {
return fmt.Errorf("Invalid operator policy: %#v", pr.Operator)
}
return nil
}
func parseCurrent(rules string, conf *Config, meta *EnterprisePolicyMeta) (*Policy, error) {
p, err := decodeRules(rules, conf, meta)
if err != nil {
return nil, err
}
if err := p.PolicyRules.Validate(conf); err != nil {
return nil, err
}
if err := p.EnterprisePolicyRules.Validate(conf); err != nil {
return nil, err
}
return p, nil
}
func parseLegacy(rules string, conf *Config) (*Policy, error) {
p := &Policy{}
type LegacyPolicy struct {
Agents []*AgentRule `hcl:"agent,expand"`
Keys []*KeyRule `hcl:"key,expand"`
Nodes []*NodeRule `hcl:"node,expand"`
Services []*ServiceRule `hcl:"service,expand"`
Sessions []*SessionRule `hcl:"session,expand"`
Events []*EventRule `hcl:"event,expand"`
PreparedQueries []*PreparedQueryRule `hcl:"query,expand"`
Keyring string `hcl:"keyring"`
Operator string `hcl:"operator"`
}
lp := &LegacyPolicy{}
if err := hcl.Decode(lp, rules); err != nil {
return nil, fmt.Errorf("Failed to parse ACL rules: %v", err)
}
// Validate the agent policy
for _, ap := range lp.Agents {
if !isPolicyValid(ap.Policy, false) {
return nil, fmt.Errorf("Invalid agent policy: %#v", ap)
}
p.AgentPrefixes = append(p.AgentPrefixes, ap)
}
// Validate the key policy
for _, kp := range lp.Keys {
if !isPolicyValid(kp.Policy, true) {
return nil, fmt.Errorf("Invalid key policy: %#v", kp)
}
if err := kp.EnterpriseRule.Validate(kp.Policy, conf); err != nil {
return nil, fmt.Errorf("Invalid key enterprise policy: %#v, got error: %v", kp, err)
}
p.KeyPrefixes = append(p.KeyPrefixes, kp)
}
// Validate the node policies
for _, np := range lp.Nodes {
if !isPolicyValid(np.Policy, false) {
return nil, fmt.Errorf("Invalid node policy: %#v", np)
}
if err := np.EnterpriseRule.Validate(np.Policy, conf); err != nil {
return nil, fmt.Errorf("Invalid node enterprise policy: %#v, got error: %v", np, err)
}
p.NodePrefixes = append(p.NodePrefixes, np)
}
// Validate the service policies
for _, sp := range lp.Services {
if !isPolicyValid(sp.Policy, false) {
return nil, fmt.Errorf("Invalid service policy: %#v", sp)
}
if sp.Intentions != "" && !isPolicyValid(sp.Intentions, false) {
return nil, fmt.Errorf("Invalid service intentions policy: %#v", sp)
}
if err := sp.EnterpriseRule.Validate(sp.Policy, conf); err != nil {
return nil, fmt.Errorf("Invalid service enterprise policy: %#v, got error: %v", sp, err)
}
p.ServicePrefixes = append(p.ServicePrefixes, sp)
}
// Validate the session policies
for _, sp := range lp.Sessions {
if !isPolicyValid(sp.Policy, false) {
return nil, fmt.Errorf("Invalid session policy: %#v", sp)
}
p.SessionPrefixes = append(p.SessionPrefixes, sp)
}
// Validate the user event policies
for _, ep := range lp.Events {
if !isPolicyValid(ep.Policy, false) {
return nil, fmt.Errorf("Invalid event policy: %#v", ep)
}
p.EventPrefixes = append(p.EventPrefixes, ep)
}
// Validate the prepared query policies
for _, pq := range lp.PreparedQueries {
if !isPolicyValid(pq.Policy, false) {
return nil, fmt.Errorf("Invalid query policy: %#v", pq)
}
p.PreparedQueryPrefixes = append(p.PreparedQueryPrefixes, pq)
}
// Validate the keyring policy - this one is allowed to be empty
if lp.Keyring != "" && !isPolicyValid(lp.Keyring, false) {
return nil, fmt.Errorf("Invalid keyring policy: %#v", lp.Keyring)
} else {
p.Keyring = lp.Keyring
}
// Validate the operator policy - this one is allowed to be empty
if lp.Operator != "" && !isPolicyValid(lp.Operator, false) {
return nil, fmt.Errorf("Invalid operator policy: %#v", lp.Operator)
} else {
p.Operator = lp.Operator
}
return p, nil
}
// NewPolicyFromSource is used to parse the specified ACL rules into an
// intermediary set of policies, before being compiled into
// the ACL
func NewPolicyFromSource(id string, revision uint64, rules string, syntax SyntaxVersion, conf *Config, meta *EnterprisePolicyMeta) (*Policy, error) {
if rules == "" {
// Hot path for empty source
return &Policy{ID: id, Revision: revision}, nil
}
var policy *Policy
var err error
switch syntax {
case SyntaxLegacy:
policy, err = parseLegacy(rules, conf)
case SyntaxCurrent:
policy, err = parseCurrent(rules, conf, meta)
default:
return nil, fmt.Errorf("Invalid rules version: %d", syntax)
}
if err == nil {
policy.ID = id
policy.Revision = revision
}
return policy, err
}
func (policy *Policy) ConvertToLegacy() *Policy {
converted := &Policy{
ID: policy.ID,
Revision: policy.Revision,
PolicyRules: PolicyRules{
ACL: policy.ACL,
Keyring: policy.Keyring,
Operator: policy.Operator,
},
}
converted.Agents = append(converted.Agents, policy.Agents...)
converted.Agents = append(converted.Agents, policy.AgentPrefixes...)
converted.Keys = append(converted.Keys, policy.Keys...)
converted.Keys = append(converted.Keys, policy.KeyPrefixes...)
converted.Nodes = append(converted.Nodes, policy.Nodes...)
converted.Nodes = append(converted.Nodes, policy.NodePrefixes...)
converted.Services = append(converted.Services, policy.Services...)
converted.Services = append(converted.Services, policy.ServicePrefixes...)
converted.Sessions = append(converted.Sessions, policy.Sessions...)
converted.Sessions = append(converted.Sessions, policy.SessionPrefixes...)
converted.Events = append(converted.Events, policy.Events...)
converted.Events = append(converted.Events, policy.EventPrefixes...)
converted.PreparedQueries = append(converted.PreparedQueries, policy.PreparedQueries...)
converted.PreparedQueries = append(converted.PreparedQueries, policy.PreparedQueryPrefixes...)
return converted
}
func (policy *Policy) ConvertFromLegacy() *Policy {
return &Policy{
ID: policy.ID,
Revision: policy.Revision,
PolicyRules: PolicyRules{
AgentPrefixes: policy.Agents,
KeyPrefixes: policy.Keys,
NodePrefixes: policy.Nodes,
ServicePrefixes: policy.Services,
SessionPrefixes: policy.Sessions,
EventPrefixes: policy.Events,
PreparedQueryPrefixes: policy.PreparedQueries,
Keyring: policy.Keyring,
Operator: policy.Operator,
},
}
}
// takesPrecedenceOver returns true when permission a
// should take precedence over permission b
func takesPrecedenceOver(a, b string) bool {
if a == PolicyDeny {
return true
} else if b == PolicyDeny {
return false
}
if a == PolicyWrite {
return true
} else if b == PolicyWrite {
return false
}
if a == PolicyList {
return true
} else if b == PolicyList {
return false
}
if a == PolicyRead {
return true
} else if b == PolicyRead {
return false
}
return false
}
func TranslateLegacyRules(policyBytes []byte) ([]byte, error) {
parsed, err := hcl.ParseBytes(policyBytes)
if err != nil {
return nil, fmt.Errorf("Failed to parse rules: %v", err)
}
rewritten := ast.Walk(parsed, func(node ast.Node) (ast.Node, bool) {
switch n := node.(type) {
case *ast.ObjectItem:
if len(n.Keys) < 1 {
return node, true
}
txt := n.Keys[0].Token.Text
if n.Keys[0].Token.Type == token.STRING {
txt, err = strconv.Unquote(txt)
if err != nil {
return node, true
}
}
switch txt {
case "policy":
n.Keys[0].Token.Text = "policy"
case "agent":
n.Keys[0].Token.Text = "agent_prefix"
case "key":
n.Keys[0].Token.Text = "key_prefix"
case "node":
n.Keys[0].Token.Text = "node_prefix"
case "query":
n.Keys[0].Token.Text = "query_prefix"
case "service":
n.Keys[0].Token.Text = "service_prefix"
case "session":
n.Keys[0].Token.Text = "session_prefix"
case "event":
n.Keys[0].Token.Text = "event_prefix"
}
}
return node, true
})
buffer := new(bytes.Buffer)
if err := hclprinter.Fprint(buffer, rewritten); err != nil {
return nil, fmt.Errorf("Failed to output new rules: %v", err)
}
return buffer.Bytes(), nil
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment