/
pano.go
299 lines (254 loc) · 8.04 KB
/
pano.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
package decryption
import (
"fmt"
"strings"
"github.com/PaloAltoNetworks/pango/audit"
"github.com/PaloAltoNetworks/pango/namespace"
"github.com/PaloAltoNetworks/pango/util"
)
// Panorama is the client.Policies.Security namespace.
//
// The "dg" param in these functions is the device group.
//
// The "base" param in these functions should be one of the rulebase
// constants in the "util" package.
type Panorama struct {
ns *namespace.Policy
}
// GetList performs GET to retrieve a list of all objects.
func (c *Panorama) GetList(dg, base string) ([]string, error) {
ans := c.container()
return c.ns.Listing(util.Get, c.pather(dg, base), ans)
}
// ShowList performs SHOW to retrieve a list of all objects.
func (c *Panorama) ShowList(dg, base string) ([]string, error) {
ans := c.container()
return c.ns.Listing(util.Show, c.pather(dg, base), ans)
}
// Get performs GET to retrieve information for the given object.
func (c *Panorama) Get(dg, base, name string) (Entry, error) {
ans := c.container()
err := c.ns.Object(util.Get, c.pather(dg, base), name, ans)
return first(ans, err)
}
// Show performs SHOW to retrieve information for the given object.
func (c *Panorama) Show(dg, base, name string) (Entry, error) {
ans := c.container()
err := c.ns.Object(util.Show, c.pather(dg, base), name, ans)
return first(ans, err)
}
// GetAll performs GET to retrieve information for all objects.
func (c *Panorama) GetAll(dg, base string) ([]Entry, error) {
ans := c.container()
err := c.ns.Objects(util.Get, c.pather(dg, base), ans)
return all(ans, err)
}
// ShowAll performs SHOW to retrieve information for all objects.
func (c *Panorama) ShowAll(dg, base string) ([]Entry, error) {
ans := c.container()
err := c.ns.Objects(util.Show, c.pather(dg, base), ans)
return all(ans, err)
}
/*
ConfigureRules configures the given rules on PAN-OS.
It does a mass SET if it can, but will EDIT any rules that are present but
differ from what is given.
Audit comments are applied only for rules which are either SET or EDIT'ed.
If isPolicy is true, then any rules not explicitly present in the rules param will
be deleted.
Params move and oRule are for moving the group into place after configuration.
Any rule name that appears in prevRules but not in the rules param will be deleted.
*/
func (c *Panorama) ConfigureRules(dg, base string, rules []Entry, auditComments map[string]string, isPolicy bool, move int, oRule string, prevNames []string) error {
var err error
setRules := make([]Entry, 0, len(rules))
editRules := make([]Entry, 0, len(rules))
curRules, err := c.GetAll(dg, base)
if err != nil {
return err
}
// Determine which can be set and which can must be edited.
for _, x := range rules {
var found bool
for _, live := range curRules {
if x.Name == live.Name {
found = true
if !RulesMatch(x, live) {
editRules = append(editRules, x)
}
break
}
}
if !found {
setRules = append(setRules, x)
}
}
// Set all rules.
if len(setRules) > 0 {
if err = c.Set(dg, base, setRules...); err != nil {
return err
}
// Configure audit comments for each set rule.
for _, x := range setRules {
if comment := auditComments[x.Name]; comment != "" {
if err = c.SetAuditComment(dg, base, x.Name, comment); err != nil {
return err
}
}
}
}
// Edit each rule one by one.
for _, x := range editRules {
if err = c.Edit(dg, base, x); err != nil {
return err
}
// Configure the audit comment for each edited rule.
if comment := auditComments[x.Name]; comment != "" {
if err = c.SetAuditComment(dg, base, x.Name, comment); err != nil {
return err
}
}
}
// Move the group into place.
if err = c.MoveGroup(dg, base, move, oRule, rules...); err != nil {
return err
}
// Delete rules removed from the group.
if len(prevNames) != 0 {
rmList := make([]interface{}, 0, len(prevNames))
for _, name := range prevNames {
var found bool
for _, x := range rules {
if x.Name == name {
found = true
break
}
}
if !found {
rmList = append(rmList, name)
}
}
if len(rmList) != 0 {
if err = c.Delete(dg, base, rmList...); err != nil {
return err
}
}
}
// Optional: If this is a policy, delete everything else.
if isPolicy {
delRules := make([]interface{}, 0, len(curRules))
for _, cur := range curRules {
var found bool
for _, x := range rules {
if x.Name == cur.Name {
found = true
break
}
}
if !found {
delRules = append(delRules, cur.Name)
}
}
if len(delRules) != 0 {
if err = c.Delete(dg, base, delRules...); err != nil {
return nil
}
}
}
return nil
}
// Set performs SET to create / update one or more objects.
func (c *Panorama) Set(dg, base string, e ...Entry) error {
err := c.ns.Set(c.pather(dg, base), specifier(e...))
// On error: find the rule that's causing the error if multiple rules
// were given.
if err != nil && strings.Contains(err.Error(), "rules is invalid") {
for i := 0; i < len(e); i++ {
if e2 := c.Set(dg, base, e[i]); e2 != nil {
return fmt.Errorf("Error with rule %d: %s", i+1, e2)
} else {
_ = c.Delete(dg, base, e[i])
}
}
// Couldn't find it, just return the original error.
return err
}
return err
}
// Edit performs EDIT to configure the specified object.
func (c *Panorama) Edit(dg, base string, e Entry) error {
return c.ns.Edit(c.pather(dg, base), e)
}
// Delete removes the given objects.
//
// Objects can be a string or an Entry object.
func (c *Panorama) Delete(dg, base string, e ...interface{}) error {
names, nErr := toNames(e)
return c.ns.Delete(c.pather(dg, base), names, nErr)
}
// FromPanosConfig retrieves the object stored in the retrieved config.
func (c *Panorama) FromPanosConfig(dg, base, name string) (Entry, error) {
ans := c.container()
err := c.ns.FromPanosConfig(c.pather(dg, base), name, ans)
return first(ans, err)
}
// AllFromPanosConfig retrieves all objects stored in the retrieved config.
func (c *Panorama) AllFromPanosConfig(dg, base string) ([]Entry, error) {
ans := c.container()
err := c.ns.AllFromPanosConfig(c.pather(dg, base), ans)
return all(ans, err)
}
// MoveGroup moves a logical group of rules somewhere in relation to another rule.
//
// The `movement` param should be one of the Move constants in the util
// package.
//
// The `rule` param is the other rule the `movement` param is referencing. If
// this is an empty string, then the first policy in the group isn't moved
// anywhere, but all other policies will still be moved to be grouped with the
// first one.
func (c *Panorama) MoveGroup(dg, base string, movement int, rule string, e ...Entry) error {
lister := func() ([]string, error) {
return c.GetList(dg, base)
}
ei := make([]interface{}, 0, len(e))
for i := range e {
ei = append(ei, e[i])
}
names, _ := toNames(ei)
return c.ns.MoveGroup(c.pather(dg, base), lister, movement, rule, names)
}
// SetAuditComment sets the audit comment for the given rule.
func (c *Panorama) SetAuditComment(dg, base, rule, comment string) error {
return c.ns.SetAuditComment(c.pather(dg, base), rule, comment)
}
// CurrentAuditComment returns the current audit comment.
func (c *Panorama) CurrentAuditComment(dg, base, rule string) (string, error) {
return c.ns.CurrentAuditComment(c.pather(dg, base), rule)
}
// AuditCommentHistory returns a chunk of historical audit comment logs.
func (c *Panorama) AuditCommentHistory(dg, base, rule, direction string, nlogs, skip int) ([]audit.Comment, error) {
return c.ns.AuditCommentHistory(c.pather(dg, base), rule, direction, nlogs, skip)
}
func (c *Panorama) pather(dg, base string) namespace.Pather {
return func(v []string) ([]string, error) {
return c.xpath(dg, base, v)
}
}
func (c *Panorama) xpath(dg, base string, vals []string) ([]string, error) {
if err := util.ValidateRulebase(dg, base); err != nil {
return nil, err
}
ans := make([]string, 0, 9)
ans = append(ans, util.DeviceGroupXpathPrefix(dg)...)
ans = append(ans,
base,
"decryption",
"rules",
util.AsEntryXpath(vals),
)
return ans, nil
}
func (c *Panorama) container() normalizer {
return container(c.ns.Client.Versioning())
}