github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/policy/checker.go (about) 1 package policy 2 3 import ( 4 "fmt" 5 "strings" 6 7 "code.cloudfoundry.org/lager" 8 "github.com/jessevdk/go-flags" 9 ) 10 11 const ActionUseImage = "UseImage" 12 13 type PolicyCheckNotPass struct { 14 Reasons []string 15 } 16 17 func (e PolicyCheckNotPass) Error() string { 18 return fmt.Sprintf("policy check failed: %s", strings.Join(e.Reasons, ", ")) 19 } 20 21 type 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 27 type 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 40 type PolicyCheckOutput struct { 41 Allowed bool 42 Reasons []string 43 } 44 45 // FailedPolicyCheck creates a generic failed check 46 func FailedPolicyCheck() PolicyCheckOutput { 47 return PolicyCheckOutput{ 48 Allowed: false, 49 Reasons: []string{}, 50 } 51 } 52 53 // PassedPolicyCheck creates a generic passed check 54 func 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. 64 type 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 72 type AgentFactory interface { 73 Description() string 74 IsConfigured() bool 75 NewAgent(lager.Logger) (Agent, error) 76 } 77 78 var agentFactories []AgentFactory 79 80 func RegisterAgent(factory AgentFactory) { 81 agentFactories = append(agentFactories, factory) 82 } 83 84 func 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 93 var ( 94 clusterName string 95 clusterVersion string 96 ) 97 98 //go:generate counterfeiter . Checker 99 100 type Checker interface { 101 ShouldCheckHttpMethod(string) bool 102 ShouldCheckAction(string) bool 103 ShouldSkipAction(string) bool 104 105 Check(input PolicyCheckInput) (PolicyCheckOutput, error) 106 } 107 108 func Initialize(logger lager.Logger, cluster string, version string, filter Filter) (Checker, error) { 109 logger.Debug("policy-checker-initialize") 110 111 clusterName = cluster 112 clusterVersion = version 113 114 var checkerDescriptions []string 115 for _, factory := range agentFactories { 116 if factory.IsConfigured() { 117 checkerDescriptions = append(checkerDescriptions, factory.Description()) 118 } 119 } 120 if len(checkerDescriptions) > 1 { 121 return nil, fmt.Errorf("Multiple policy checker configured: %s", strings.Join(checkerDescriptions, ", ")) 122 } 123 124 for _, factory := range agentFactories { 125 if factory.IsConfigured() { 126 agent, err := factory.NewAgent(logger.Session("policy-checker")) 127 if err != nil { 128 return nil, err 129 } 130 131 logger.Info("warning-experiment-policy-check", 132 lager.Data{"rfc": "https://github.com/concourse/rfcs/pull/41"}) 133 134 return &AgentChecker{ 135 filter: filter, 136 agent: agent, 137 }, nil 138 } 139 } 140 141 // No policy checker configured. 142 return NoopChecker{}, nil 143 } 144 145 type AgentChecker struct { 146 filter Filter 147 agent Agent 148 } 149 150 func (c *AgentChecker) ShouldCheckHttpMethod(method string) bool { 151 return inArray(c.filter.HttpMethods, method) 152 } 153 154 func (c *AgentChecker) ShouldCheckAction(action string) bool { 155 return inArray(c.filter.Actions, action) 156 } 157 158 func (c *AgentChecker) ShouldSkipAction(action string) bool { 159 return inArray(c.filter.ActionsToSkip, action) 160 } 161 162 func inArray(array []string, target string) bool { 163 found := false 164 for _, ele := range array { 165 if ele == target { 166 found = true 167 break 168 } 169 } 170 return found 171 } 172 173 func (c *AgentChecker) Check(input PolicyCheckInput) (PolicyCheckOutput, error) { 174 input.Service = "concourse" 175 input.ClusterName = clusterName 176 input.ClusterVersion = clusterVersion 177 return c.agent.Check(input) 178 } 179 180 type NoopChecker struct{} 181 182 func (noop NoopChecker) ShouldCheckHttpMethod(string) bool { return false } 183 func (noop NoopChecker) ShouldCheckAction(string) bool { return false } 184 func (noop NoopChecker) ShouldSkipAction(string) bool { return true } 185 186 func (noop NoopChecker) Check(PolicyCheckInput) (PolicyCheckOutput, error) { 187 return PolicyCheckOutput{Allowed: true}, nil 188 }