1package policy 2 3import ( 4 "fmt" 5 "strings" 6 7 "code.cloudfoundry.org/lager" 8 "github.com/jessevdk/go-flags" 9) 10 11const ActionUseImage = "UseImage" 12 13type PolicyCheckNotPass struct { 14 Reasons []string 15} 16 17func (e PolicyCheckNotPass) Error() string { 18 return fmt.Sprintf("policy check failed: %s", strings.Join(e.Reasons, ", ")) 19} 20 21type Filter struct { 22 HttpMethods []string `long:"policy-check-filter-http-method" description:"API http method to go through policy check"` 23 Actions []string `long:"policy-check-filter-action" description:"Actions in the list will go through policy check"` 24 ActionsToSkip []string `long:"policy-check-filter-action-skip" description:"Actions the list will not go through policy check"` 25} 26 27type PolicyCheckInput struct { 28 Service string `json:"service"` 29 ClusterName string `json:"cluster_name"` 30 ClusterVersion string `json:"cluster_version"` 31 HttpMethod string `json:"http_method,omitempty"` 32 Action string `json:"action"` 33 User string `json:"user,omitempty"` 34 Team string `json:"team,omitempty"` 35 Roles []string `json:"roles,omitempty"` 36 Pipeline string `json:"pipeline,omitempty"` 37 Data interface{} `json:"data,omitempty"` 38} 39 40type PolicyCheckOutput struct { 41 Allowed bool 42 Reasons []string 43} 44 45// FailedPolicyCheck creates a generic failed check 46func FailedPolicyCheck() PolicyCheckOutput { 47 return PolicyCheckOutput{ 48 Allowed: false, 49 Reasons: []string{}, 50 } 51} 52 53// PassedPolicyCheck creates a generic passed check 54func PassedPolicyCheck() PolicyCheckOutput { 55 return PolicyCheckOutput{ 56 Allowed: true, 57 Reasons: []string{}, 58 } 59} 60 61//go:generate counterfeiter . Agent 62 63// Agent should be implemented by policy agents. 64type Agent interface { 65 // Check returns true if passes policy check. If not goes through policy 66 // check, just return true. 67 Check(PolicyCheckInput) (PolicyCheckOutput, error) 68} 69 70//go:generate counterfeiter . AgentFactory 71 72type AgentFactory interface { 73 Description() string 74 IsConfigured() bool 75 NewAgent(lager.Logger) (Agent, error) 76} 77 78var agentFactories []AgentFactory 79 80func RegisterAgent(factory AgentFactory) { 81 agentFactories = append(agentFactories, factory) 82} 83 84func WireCheckers(group *flags.Group) { 85 for _, factory := range agentFactories { 86 _, err := group.AddGroup(fmt.Sprintf("Policy Check Agent (%s)", factory.Description()), "", factory) 87 if err != nil { 88 panic(err) 89 } 90 } 91} 92 93var ( 94 clusterName string 95 clusterVersion string 96) 97 98func Initialize(logger lager.Logger, cluster string, version string, filter Filter) (*Checker, error) { 99 logger.Debug("policy-checker-initialize") 100 101 clusterName = cluster 102 clusterVersion = version 103 104 var checkerDescriptions []string 105 for _, factory := range agentFactories { 106 if factory.IsConfigured() { 107 checkerDescriptions = append(checkerDescriptions, factory.Description()) 108 } 109 } 110 if len(checkerDescriptions) > 1 { 111 return nil, fmt.Errorf("Multiple policy checker configured: %s", strings.Join(checkerDescriptions, ", ")) 112 } 113 114 for _, factory := range agentFactories { 115 if factory.IsConfigured() { 116 agent, err := factory.NewAgent(logger.Session("policy-checker")) 117 if err != nil { 118 return nil, err 119 } 120 121 logger.Info("warning-experiment-policy-check", 122 lager.Data{"rfc": "https://github.com/concourse/rfcs/pull/41"}) 123 124 return &Checker{ 125 filter: filter, 126 agent: agent, 127 }, nil 128 } 129 } 130 131 // No policy checker configured. 132 return nil, nil 133} 134 135type Checker struct { 136 filter Filter 137 agent Agent 138} 139 140func (c *Checker) ShouldCheckHttpMethod(method string) bool { 141 return inArray(c.filter.HttpMethods, method) 142} 143 144func (c *Checker) ShouldCheckAction(action string) bool { 145 return inArray(c.filter.Actions, action) 146} 147 148func (c *Checker) ShouldSkipAction(action string) bool { 149 return inArray(c.filter.ActionsToSkip, action) 150} 151 152func inArray(array []string, target string) bool { 153 found := false 154 for _, ele := range array { 155 if ele == target { 156 found = true 157 break 158 } 159 } 160 return found 161} 162 163func (c *Checker) Check(input PolicyCheckInput) (PolicyCheckOutput, error) { 164 input.Service = "concourse" 165 input.ClusterName = clusterName 166 input.ClusterVersion = clusterVersion 167 return c.agent.Check(input) 168} 169