-
Notifications
You must be signed in to change notification settings - Fork 90
/
openshift.go
114 lines (94 loc) · 4.21 KB
/
openshift.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
package k8sutil
import (
"context"
"strconv"
"strings"
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
"github.com/pkg/errors"
"github.com/replicatedhq/kots/pkg/util"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
// IsOpenShift returns true if the cluster is positively identified as being an openshift cluster
func IsOpenShift(clientset kubernetes.Interface) bool {
// ignore errors, since resources might be returned anyways
// ignore groups, since we only need the data contained in resources
_, resources, _ := clientset.Discovery().ServerGroupsAndResources()
if resources != nil {
for _, resource := range resources {
if strings.Contains(resource.GroupVersion, "openshift") {
return true
}
}
}
return false
}
// GetOpenShiftPodSecurityContext returns a PodSecurityContext object that has:
// RunAsUser set to the minimum value in the "openshift.io/sa.scc.uid-range" annotation.
// FSGroup set to the minimum value in the "openshift.io/sa.scc.supplemental-groups" annotation if exists, else falls back to the minimum value in the "openshift.io/sa.scc.uid-range" annotation.
func GetOpenShiftPodSecurityContext(kotsadmNamespace string) (*corev1.PodSecurityContext, error) {
clientset, err := GetClientset()
if err != nil {
return nil, errors.Wrap(err, "failed to get clientset")
}
ns, err := clientset.CoreV1().Namespaces().Get(context.TODO(), kotsadmNamespace, metav1.GetOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed to get namespace")
}
// uid-range annotation must exist, otherwise the SCC will fail to create
// reference: check the 1st note at the bottom of the page https://docs.openshift.com/enterprise/3.1/architecture/additional_concepts/authorization.html#admission
uidRange, ok := ns.ObjectMeta.Annotations["openshift.io/sa.scc.uid-range"]
if !ok {
return nil, errors.New("annotation 'openshift.io/sa.scc.uid-range' not found")
}
supplementalGroups, ok := ns.ObjectMeta.Annotations["openshift.io/sa.scc.supplemental-groups"]
if !ok {
// fsgroup and supplemental groups strategies fall back to the uid-range annotation if the supplemental-groups annotation does not exist
// reference: check the 1st note at the bottom of the page https://docs.openshift.com/enterprise/3.1/architecture/additional_concepts/authorization.html#admission
supplementalGroups = uidRange
}
// supplemental groups annotation can contain multiple ranges separated by commas. get the first one.
// reference: check the 3rd note at the bottom of the page https://docs.openshift.com/enterprise/3.1/architecture/additional_concepts/authorization.html#admission
supplementalGroups = strings.Split(supplementalGroups, ",")[0]
uidStr := strings.Split(uidRange, "/")[0]
fsGroupStr := strings.Split(supplementalGroups, "/")[0] // use the minimum value of the supplemental groups range as fsgroup. reference: https://www.openshift.com/blog/a-guide-to-openshift-and-uids
uid, err := strconv.Atoi(uidStr)
if err != nil {
return nil, errors.Wrap(err, "failed to convert uid to integer")
}
fsGroup, err := strconv.Atoi(fsGroupStr)
if err != nil {
return nil, errors.Wrap(err, "failed to convert fsgroup to integer")
}
psc := &corev1.PodSecurityContext{
RunAsUser: util.IntPointer(uid),
FSGroup: util.IntPointer(fsGroup),
}
return psc, nil
}
func OpenShiftVersion() (string, error) {
// openshift-apiserver does not report version,
// clusteroperator/openshift-apiserver does, and only version number
cfg, err := GetClusterConfig()
if err != nil {
return "", errors.Wrap(err, "failed to get cluster config")
}
client, err := configv1client.NewForConfig(cfg)
if err != nil {
return "", errors.Wrap(err, "failed to build client from config")
}
clusterOperator, err := client.ClusterOperators().Get(context.TODO(), "openshift-apiserver", metav1.GetOptions{})
if err != nil {
return "", errors.Wrap(err, "failed to get openshift apiserver")
}
if clusterOperator == nil {
return "", errors.New("no openshift apiserver found")
}
for _, ver := range clusterOperator.Status.Versions {
if ver.Name == "operator" {
return ver.Version, nil
}
}
return "", errors.New("no openshift operator found")
}