Skip to content

Commit 9ed3ec7

Browse files
Merge pull request #86 from martinkunc/collect-configmap
Collecting config maps
2 parents d0cc5df + 1d33a3b commit 9ed3ec7

File tree

5 files changed

+280
-16
lines changed

5 files changed

+280
-16
lines changed

pkg/gather/clusterconfig/clusterconfig.go

+60
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import (
1414
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
1515
certificatesv1beta1 "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
1616

17+
"encoding/base64"
18+
"encoding/pem"
19+
1720
corev1 "k8s.io/api/core/v1"
1821
"k8s.io/apimachinery/pkg/api/errors"
1922
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -140,6 +143,23 @@ func (i *Gatherer) Gather(ctx context.Context, recorder record.Interface) error
140143

141144
return records, nil
142145
},
146+
func() ([]record.Record, []error) {
147+
cms, err := i.coreClient.ConfigMaps("openshift-config").List(metav1.ListOptions{})
148+
if err != nil {
149+
return nil, []error{err}
150+
}
151+
records := make([]record.Record, 0, len(cms.Items))
152+
for i := range cms.Items {
153+
for dk, dv := range cms.Items[i].Data {
154+
records = append(records, record.Record{Name: fmt.Sprintf("config/configmaps/%s/%s", cms.Items[i].Name, dk), Item: ConfigMapAnonymizer{v: []byte(dv), encodeBase64: false}})
155+
}
156+
for dk, dv := range cms.Items[i].BinaryData {
157+
records = append(records, record.Record{Name: fmt.Sprintf("config/configmaps/%s/%s", cms.Items[i].Name, dk), Item: ConfigMapAnonymizer{v: dv, encodeBase64: true}})
158+
}
159+
}
160+
161+
return records, nil
162+
},
143163
func() ([]record.Record, []error) {
144164
config, err := i.client.ClusterVersions().Get("version", metav1.GetOptions{})
145165
if errors.IsNotFound(err) {
@@ -543,3 +563,43 @@ func (i *Gatherer) ClusterVersion() *configv1.ClusterVersion {
543563
defer i.lock.Unlock()
544564
return i.lastVersion
545565
}
566+
567+
// ConfigMapAnonymizer implements serialization of configmap
568+
// and potentially anonymizes if it is a certificate
569+
type ConfigMapAnonymizer struct {
570+
v []byte
571+
encodeBase64 bool
572+
}
573+
574+
// Marshal implements serialization of Node with anonymization
575+
func (a ConfigMapAnonymizer) Marshal(_ context.Context) ([]byte, error) {
576+
c := []byte(anonymizeConfigMap(a.v))
577+
if a.encodeBase64 {
578+
buff := make([]byte, base64.StdEncoding.EncodedLen(len(c)))
579+
base64.StdEncoding.Encode(buff, []byte(c))
580+
c = buff
581+
}
582+
return c, nil
583+
}
584+
585+
func anonymizeConfigMap(dv []byte) string {
586+
anonymizedPemBlock := `-----BEGIN CERTIFICATE-----
587+
ANONYMIZED
588+
-----END CERTIFICATE-----
589+
`
590+
var sb strings.Builder
591+
r := dv
592+
for {
593+
var block *pem.Block
594+
block, r = pem.Decode(r)
595+
if block == nil {
596+
// cannot be extracted
597+
return string(dv)
598+
}
599+
sb.WriteString(anonymizedPemBlock)
600+
if len(r) == 0 {
601+
break
602+
}
603+
}
604+
return sb.String()
605+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package clusterconfig
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"io/ioutil"
7+
"os"
8+
"testing"
9+
10+
"github.com/openshift/insights-operator/pkg/record"
11+
"github.com/openshift/insights-operator/pkg/utils"
12+
v1 "k8s.io/api/core/v1"
13+
"k8s.io/klog"
14+
)
15+
16+
func TestConfigMapAnonymizer(t *testing.T) {
17+
klog.SetOutput(utils.NewTestLog(t).Writer())
18+
19+
var cases = []struct {
20+
testName string
21+
configMapName string
22+
expectedAnonymizedJSON string
23+
}{
24+
{
25+
"ConfigMap Non PEM data",
26+
"openshift-install",
27+
`{
28+
"invoker":"codeReadyContainers",
29+
"version":"unreleased-master-2205-g2055609f95b19322ee6cfdd0bea73399297c4a3e"
30+
}`,
31+
},
32+
{
33+
"ConfigMap PEM is anonymized",
34+
"initial-kube-apiserver-server-ca",
35+
`{
36+
"ca-bundle.crt": "-----BEGIN CERTIFICATE-----\nANONYMIZED\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nANONYMIZED\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nANONYMIZED\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nANONYMIZED\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nANONYMIZED\n-----END CERTIFICATE-----\n"
37+
}`,
38+
},
39+
{
40+
"ConfigMap BinaryData non anonymized",
41+
"test-binary",
42+
`{
43+
"ls": "z/rt/gcAAAEDAA=="
44+
}`,
45+
},
46+
}
47+
48+
for _, tt := range cases {
49+
t.Run(tt.testName, func(t *testing.T) {
50+
f, err := os.Open("testdata/configmaps.json")
51+
mustNotFail(t, err, "error opening test data file. %+v")
52+
defer f.Close()
53+
bts, err := ioutil.ReadAll(f)
54+
mustNotFail(t, err, "error reading test data file. %+v")
55+
var cml *v1.ConfigMapList
56+
mustNotFail(t, json.Unmarshal([]byte(bts), &cml), "error unmarshalling json %+v")
57+
cm := findMap(cml, tt.configMapName)
58+
mustNotFail(t, cm != nil, "haven't found a ConfigMap %+v")
59+
var res []byte
60+
cmdata := map[string]string{}
61+
addAnonymized := func(cmdata map[string]string, dn string, encodebase64 bool, d []byte) {
62+
m := record.Marshalable(ConfigMapAnonymizer{v: d, encodeBase64: encodebase64})
63+
64+
res, err = m.Marshal(context.TODO())
65+
cmdata[dn] = string(res)
66+
mustNotFail(t, err, "serialization failed %+v")
67+
}
68+
for dn, dv := range cm.Data {
69+
addAnonymized(cmdata, dn, false, []byte(dv))
70+
}
71+
for dn, dv := range cm.BinaryData {
72+
addAnonymized(cmdata, dn, true, dv)
73+
}
74+
var md []byte
75+
md, err = json.Marshal(cmdata)
76+
mustNotFail(t, err, "marshaling failed %+v")
77+
d := map[string]string{}
78+
err = json.Unmarshal([]byte(tt.expectedAnonymizedJSON), &d)
79+
mustNotFail(t, err, "unmarshaling of expected failed %+v")
80+
exp, err := json.Marshal(d)
81+
mustNotFail(t, err, "marshaling of expected failed %+v")
82+
if string(exp) != string(md) {
83+
t.Fatalf("The test %s result is unexpected. Result: \n%s \nExpected \n%s", tt.testName, string(md), string(exp))
84+
}
85+
})
86+
}
87+
88+
}
89+
90+
func mustNotFail(t *testing.T, err interface{}, fmtstr string) {
91+
if e, ok := err.(error); ok && e != nil {
92+
t.Fatalf(fmtstr, e)
93+
}
94+
if e, ok := err.(bool); ok && !e {
95+
t.Fatalf(fmtstr, e)
96+
}
97+
}
98+
99+
func findMap(cml *v1.ConfigMapList, name string) *v1.ConfigMap {
100+
for _, it := range cml.Items {
101+
if it.Name == name {
102+
return &it
103+
}
104+
}
105+
return nil
106+
}

pkg/gather/clusterconfig/csr.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"fmt"
99
"time"
1010

11-
"github.com/openshift/insights-operator/pkg/utils"
1211
"k8s.io/api/certificates/v1beta1"
1312
certificatesv1b1api "k8s.io/api/certificates/v1beta1"
1413
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -130,18 +129,18 @@ func anonymizeCSRRequest(r *certificatesv1b1api.CertificateSigningRequest, c *CS
130129

131130
c.Spec.Request.SignatureAlgorithm = csr.SignatureAlgorithm.String()
132131
c.Spec.Request.PublicKeyAlgorithm = csr.PublicKeyAlgorithm.String()
133-
c.Spec.Request.DNSNames = utils.Map(csr.DNSNames, anonymizeURL)
134-
c.Spec.Request.EmailAddresses = utils.Map(csr.EmailAddresses, anonymizeURL)
132+
c.Spec.Request.DNSNames = Map(csr.DNSNames, anonymizeURL)
133+
c.Spec.Request.EmailAddresses = Map(csr.EmailAddresses, anonymizeURL)
135134
ipsl := make([]string, len(csr.IPAddresses))
136135
for i, ip := range csr.IPAddresses {
137136
ipsl[i] = ip.String()
138137
}
139-
c.Spec.Request.IPAddresses = utils.Map(ipsl, anonymizeURL)
138+
c.Spec.Request.IPAddresses = Map(ipsl, anonymizeURL)
140139
urlsl := make([]string, len(csr.URIs))
141140
for i, u := range csr.URIs {
142141
urlsl[i] = u.String()
143142
}
144-
c.Spec.Request.URIs = utils.Map(urlsl, anonymizeURL)
143+
c.Spec.Request.URIs = Map(urlsl, anonymizeURL)
145144
}
146145

147146
func anonymizePkxName(s pkix.Name) (a pkix.Name) {
@@ -166,7 +165,7 @@ func anonymizePkxName(s pkix.Name) (a pkix.Name) {
166165
case *string:
167166
*(dst[i].(*string)) = anonymizeString(*s)
168167
case *[]string:
169-
*(dst[i].(*[]string)) = utils.Map(*s, anonymizeString)
168+
*(dst[i].(*[]string)) = Map(*s, anonymizeString)
170169
default:
171170
panic(fmt.Sprintf("unknown type %T", s))
172171
}
@@ -223,6 +222,15 @@ func anonymizeCSR(r *certificatesv1b1api.CertificateSigningRequest) *CSRAnonymiz
223222
return c
224223
}
225224

225+
// Map applies each of functions to passed slice
226+
func Map(it []string, fn func(string) string) []string {
227+
outSlice := []string{}
228+
for _, str := range it {
229+
outSlice = append(outSlice, fn(str))
230+
}
231+
return outSlice
232+
}
233+
226234
type CSRAnonymizedFeatures struct {
227235
TypeMeta metav1.TypeMeta
228236
ObjectMeta metav1.ObjectMeta

0 commit comments

Comments
 (0)