-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #256 from rancher/dev/v0.3
Dev/v0.3
- Loading branch information
Showing
45 changed files
with
1,326 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# core/v1 | ||
|
||
## Namespace | ||
|
||
### Validation Checks | ||
|
||
Note: The kube-system namespace, unlike other namespaces, has a "failPolicy" of "ignore" on update calls. | ||
|
||
#### PSA Label Validation | ||
|
||
Validates that users who create or edit a PSA enforcement label on a namespace have the `updatepsa` verb on `projects` in `management.cattle.io/v3`. See the [upstream docs](https://kubernetes.io/docs/concepts/security/pod-security-admission/) for more information on the effect of these labels. | ||
|
||
The following labels are considered relevant labels for PSA enforcement: `"pod-security.kubernetes.io/enforce", "pod-security.kubernetes.io/enforce-version", "pod-security.kubernetes.io/audit", "pod-security.kubernetes.io/audit-version", "pod-security.kubernetes.io/warn", "pod-security.kubernetes.io/warn-version"`. | ||
|
||
# management.cattle.io/v3 | ||
|
||
## ClusterRoleTemplateBinding | ||
|
||
### Validation Checks | ||
|
||
#### Escalation Prevention | ||
|
||
Users can only create/update ClusterRoleTemplateBindings which grant permissions to RoleTemplates with rights less than or equal to those they currently possess. This is to prevent privilege escalation. | ||
|
||
#### Invalid Fields - Create | ||
|
||
Users cannot create ClusterRoleTemplateBindings which violate the following constraints: | ||
- Either a user subject (through "UserName" or "UserPrincipalName") or a group subject (through "GroupName" or "GroupPrincipalName") must be specified; both a user subject and group subject cannot be specified | ||
- A "ClusterName" must be specified | ||
- The roleTemplate indicated in "RoleTemplateName" must be: | ||
- Valid (i.e. is an existing `roleTemplate` object in the `management.cattle.io/v3` apiGroup) | ||
- Not locked (i.e. `roleTemplate.Locked` must be `false`) | ||
|
||
#### Invalid Fields - Update | ||
|
||
Users cannot update the following fields after creation: | ||
- RoleTemplateName | ||
- ClusterName | ||
|
||
Users can update the following fields if they have not been set, but after they have been set they cannot be changed: | ||
- UserName | ||
- UserPrincipalName | ||
- GroupName | ||
- GroupPrincipalName | ||
|
||
In addition, as in the create validation, both a user subject and a group subject cannot be specified. | ||
|
||
## GlobalRole | ||
|
||
### Validation Checks | ||
|
||
Note: all checks are bypassed if the GlobalRole is being deleted | ||
|
||
#### Escalation Prevention | ||
|
||
Users can only change GlobalRoles with rights less than or equal to those they currently possess. This is to prevent privilege escalation. | ||
|
||
## GlobalRoleBinding | ||
|
||
### Validation Checks | ||
|
||
Note: all checks are bypassed if the GlobalRoleBinding is being deleted | ||
|
||
#### Escalation Prevention | ||
|
||
Users can only create/update GlobalRoleBindings with rights less than or equal to those they currently possess. This is to prevent privilege escalation. | ||
|
||
#### Valid Global Role Reference | ||
|
||
GlobalRoleBindings must refer to a valid global role (i.e. an existing `GlobalRole` object in the `management.cattle.io/v3` apiGroup). | ||
|
||
## NodeDriver | ||
|
||
### Validation Checks | ||
|
||
Note: checks only run if a node driver is being disabled or deleted | ||
|
||
#### Machine Deletion Prevention | ||
|
||
This admission webhook prevents the disabling or deletion of a NodeDriver if there are any Nodes that are under management by said driver. If there are _any_ nodes that use the driver the request will be denied. | ||
|
||
## ProjectRoleTemplateBinding | ||
|
||
### Validation Checks | ||
|
||
#### Escalation Prevention | ||
|
||
Users can only create/update ProjectRoleTemplateBindings with rights less than or equal to those they currently possess. This is to prevent privilege escalation. | ||
|
||
#### Invalid Fields - Create | ||
|
||
Users cannot create ProjectRoleTemplateBindings which violate the following constraints: | ||
- Either a user subject (through "UserName" or "UserPrincipalName") or a group subject (through "GroupName" or "GroupPrincipalName") must be specified; both a user subject and group subject cannot be specified | ||
- A "ProjectName" must be specified | ||
- The roleTemplate indicated in "RoleTemplateName" must be: | ||
- Valid (i.e. is an existing `roleTemplate` object in the `management.cattle.io/v3` apiGroup) | ||
- Not locked (i.e. `roleTemplate.Locked` must be `false`) | ||
|
||
#### Invalid Fields - Update | ||
|
||
Users cannot update the following fields after creation: | ||
- RoleTemplateName | ||
- ProjectName | ||
|
||
Users can update the following fields if they have not been set, but after they have been set they cannot be changed: | ||
- UserName | ||
- UserPrincipalName | ||
- GroupName | ||
- GroupPrincipalName | ||
|
||
In addition, as in the create validation, both a user subject and a group subject cannot be specified. | ||
|
||
## RoleTemplate | ||
|
||
### Validation Checks | ||
|
||
Note: all checks are bypassed if the RoleTemplate is being deleted | ||
|
||
#### Circular Reference | ||
|
||
Circular references to webhooks (a inherits b, b inherits a) are not allowed. More specifically, if "roleTemplate1" is included in the `roleTemplateNames` of "roleTemplate2", then "roleTemplate2" must not be included in the `roleTemplateNames` of "roleTemplate1". This checks prevents the creation of roles whose end-state cannot be resolved. | ||
|
||
#### Rules Without Verbs | ||
|
||
Rules without verbs are not permitted. The `rules` included in a roleTemplate are of the same type as the rules used by standard kubernetes RBAC types (such as `Roles` from `rbac.authorization.k8s.io/v1`). Because of this, they inherit the same restrictions as these types, including this one. | ||
|
||
#### Escalation Prevention | ||
|
||
Users can only change RoleTemplates with rights less than or equal to those they currently possess. This prevents privilege escalation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
FROM registry.suse.com/bci/bci-micro:15.4.19.2 | ||
FROM registry.suse.com/bci/bci-micro:15.4.20.1 | ||
|
||
ARG user=webhook | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"bytes" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"golang.org/x/exp/slices" | ||
"golang.org/x/text/cases" | ||
"golang.org/x/text/language" | ||
) | ||
|
||
// docFileName defines the name of the files that will be aggregated into overall docs | ||
const docFileExtension = ".md" | ||
|
||
type docFile struct { | ||
content []byte | ||
resource string | ||
group string | ||
version string | ||
} | ||
|
||
func generateDocs(resourcesBaseDir, outputFilePath string) (err error) { | ||
outputFile, err := os.OpenFile(outputFilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) | ||
defer func() { | ||
closeErr := outputFile.Close() | ||
if closeErr != nil { | ||
if err != nil { | ||
err = fmt.Errorf("%w, error when closing file %s", err, closeErr.Error()) | ||
} else { | ||
err = closeErr | ||
} | ||
} | ||
}() | ||
if err != nil { | ||
return err | ||
} | ||
docFiles, err := getDocFiles(resourcesBaseDir) | ||
if err != nil { | ||
return fmt.Errorf("unable to create documentation: %w", err) | ||
} | ||
currentGroup := "" | ||
for _, docFile := range docFiles { | ||
newGroup := docFile.group | ||
if newGroup != currentGroup { | ||
// our group has changed, output a new group header | ||
groupFormatString := "# %s/%s \n" | ||
if currentGroup != "" { | ||
groupFormatString = "\n" + groupFormatString | ||
} | ||
_, err = fmt.Fprintf(outputFile, groupFormatString, docFile.group, docFile.version) | ||
if err != nil { | ||
return fmt.Errorf("unable to write group header for %s/%s: %w", docFile.group, docFile.version, err) | ||
} | ||
currentGroup = newGroup | ||
} | ||
|
||
_, err = fmt.Fprintf(outputFile, "\n## %s \n\n", docFile.resource) | ||
if err != nil { | ||
return fmt.Errorf("unable to write resource header for %s: %w", docFile.resource, err) | ||
} | ||
scanner := bufio.NewScanner(bytes.NewReader(docFile.content)) | ||
for scanner.Scan() { | ||
line := scanner.Bytes() | ||
// even if the scanned line is empty, still need to output the newline | ||
if len(line) != 0 && line[0] == '#' { | ||
// this line is a markdown header. Since the group header is the top-level indent, indent this down one line | ||
line = append([]byte{'#'}, line...) | ||
} | ||
line = append(line, byte('\n')) | ||
_, err := outputFile.Write(line) | ||
if err != nil { | ||
return fmt.Errorf("unable to write content for %s/%s.%s: %w", docFile.group, docFile.version, docFile.resource, err) | ||
} | ||
|
||
} | ||
|
||
} | ||
return nil | ||
} | ||
|
||
// getDocFiles finds all markdown files recursively in resourcesBaseDir and converts them to docFiles. Returns in a sorted order, | ||
// first by group, then by resourceName | ||
func getDocFiles(baseDir string) ([]docFile, error) { | ||
entries, err := os.ReadDir(baseDir) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to list entries in directory %s: %w", baseDir, err) | ||
} | ||
var docFiles []docFile | ||
for _, entry := range entries { | ||
entryPath := filepath.Join(baseDir, entry.Name()) | ||
if entry.IsDir() { | ||
subDocFiles, err := getDocFiles(entryPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
docFiles = append(docFiles, subDocFiles...) | ||
continue | ||
} | ||
if filepath.Ext(entry.Name()) != docFileExtension { | ||
continue | ||
} | ||
content, err := os.ReadFile(filepath.Join(baseDir, entry.Name())) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to read file content for %s: %w", entryPath, err) | ||
} | ||
// lop off the last trailing new line to keep consistent spacing for later on | ||
if content[len(content)-1] == '\n' { | ||
content = content[:len(content)-1] | ||
} | ||
newDir, _ := filepath.Split(baseDir) | ||
newDir, version := filepath.Split(newDir[:len(newDir)-1]) | ||
newDir, group := filepath.Split(newDir[:len(newDir)-1]) | ||
resource := strings.TrimSuffix(entry.Name(), docFileExtension) | ||
if newDir == "" || resource == "" || version == "" || group == "" { | ||
return nil, fmt.Errorf("unable to extract gvr from %s, got group %s, version %s, resource %s", baseDir, group, version, resource) | ||
} | ||
// group and version need to have a consistent case so that test.cattle.io/v3 and test.cattle.Io/V3 are grouped the same way | ||
caser := cases.Lower(language.English) | ||
docFiles = append(docFiles, docFile{ | ||
content: content, | ||
resource: resource, | ||
group: caser.String(group), | ||
version: caser.String(version), | ||
}) | ||
} | ||
// if the groups differ, sort based on the group. If the groups are the same, sort based on the resource | ||
slices.SortFunc(docFiles, func(a, b docFile) bool { | ||
if a.group == b.group { | ||
if a.resource == b.resource { | ||
return a.version < b.version | ||
} | ||
return a.resource == b.resource | ||
} | ||
return a.group < b.group | ||
}) | ||
|
||
return docFiles, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.