Skip to content

Commit d71ad3a

Browse files
committed
move to crds
1 parent 35823bc commit d71ad3a

File tree

6 files changed

+108
-100
lines changed

6 files changed

+108
-100
lines changed

operator-experiment/0-instanced-challenge-crd.yaml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,8 @@ spec:
1616
spec:
1717
type: object
1818
properties:
19-
resources:
20-
type: array
21-
items:
22-
type: object
23-
x-kubernetes-embedded-resource: true
24-
x-kubernetes-preserve-unknown-fields: true
19+
challengeTemplate:
20+
type: string
2521
scope: Namespaced
2622
names:
2723
plural: instancedchallenges
Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,93 @@
11
apiVersion: "k8s.maplebacon.org/unstable"
22
kind: InstancedChallenge
33
metadata:
4-
name: nginx
4+
name: blade-runner
55
namespace: challenges
66
spec:
7-
resources:
8-
- apiVersion: apps/v1
7+
challengeTemplate: |
8+
---
9+
apiVersion: v1
10+
kind: Service
11+
metadata:
12+
name: blade-runner-{{.ID}}
13+
namespace: challenges
14+
spec:
15+
ports:
16+
- name: web
17+
port: 6969
18+
targetPort: 6969
19+
protocol: TCP
20+
selector:
21+
app: blade-runner-{{.ID}}
22+
---
23+
apiVersion: apps/v1
924
kind: Deployment
1025
metadata:
11-
name: nginx-deployment
26+
name: blade-runner-{{.ID}}
27+
labels:
28+
app: blade-runner-{{.ID}}
1229
namespace: challenges
1330
spec:
1431
selector:
1532
matchLabels:
16-
app: nginx
17-
replicas: 2
33+
app: blade-runner-{{.ID}}
34+
replicas: 1
1835
template:
1936
metadata:
2037
labels:
21-
app: nginx
38+
app: blade-runner-{{.ID}}
2239
spec:
40+
enableServiceLinks: false
41+
automountServiceAccountToken: false
2342
containers:
24-
- name: nginx
25-
image: nginx:1.14.2
43+
- name: blade-runner
44+
image: us.gcr.io/maplectf/blade-runner:latest
45+
imagePullPolicy: Always
2646
ports:
27-
- containerPort: 80
28-
- apiVersion: v1
29-
kind: Service
30-
metadata:
31-
name: nginx-service
32-
namespace: challenges
33-
spec:
34-
selector:
35-
app: nginx
36-
ports:
37-
- name: http
38-
protocol: TCP
39-
port: 8080
40-
targetPort: 80
41-
- apiVersion: networking.k8s.io/v1
47+
- containerPort: 6969
48+
name: web
49+
securityContext:
50+
allowPrivilegeEscalation: false
51+
privileged: false
52+
resources:
53+
requests:
54+
cpu: "75m"
55+
memory: "70Mi"
56+
limits:
57+
cpu: "250m"
58+
memory: "100Mi"
59+
- name: redis
60+
image: redis:latest
61+
imagePullPolicy: Always
62+
ports:
63+
- containerPort: 6379
64+
name: redis
65+
securityContext:
66+
allowPrivilegeEscalation: false
67+
privileged: false
68+
---
69+
apiVersion: networking.k8s.io/v1
4270
kind: Ingress
4371
metadata:
44-
name: nginx
72+
name: blade-runner-{{.ID}}
4573
namespace: challenges
4674
annotations:
47-
cert-manager.io/issuer: "letsencrypt-prod"
75+
certmanager.k8s.io/issuer: "letsencrypt-prod"
76+
certmanager.k8s.io/acme-challenge-type: dns01
4877
spec:
49-
ingressClassName: nginx
78+
ingressClassName: challenges-nginx
5079
tls:
5180
- hosts:
52-
- nginx-test.ctf.maplebacon.org
53-
secretName: nginx-test-tls
81+
- "{{.ID}}.blade-runner.ctf.maplebacon.org"
82+
secretName: blade-runner-tls
5483
rules:
55-
- host: nginx-test.ctf.maplebacon.org
84+
- host: {{.ID}}.blade-runner.ctf.maplebacon.org
5685
http:
5786
paths:
5887
- path: /
5988
pathType: Prefix
6089
backend:
6190
service:
62-
name: nginx-service
91+
name: blade-runner-{{.ID}}
6392
port:
64-
number: 8080
65-
- apiVersion: cert-manager.io/v1
66-
kind: Issuer
67-
metadata:
68-
name: letsencrypt-prod
69-
namespace: challenges
70-
spec:
71-
acme:
72-
# The ACME server URL
73-
server: https://acme-v02.api.letsencrypt.org/directory
74-
# Email address used for ACME registration
75-
76-
# Name of a secret used to store the ACME account private key
77-
privateKeySecretRef:
78-
name: letsencrypt-prod
79-
# Enable the HTTP-01 challenge provider
80-
solvers:
81-
- http01:
82-
ingress:
83-
class: nginx
93+
number: 6969

src/db.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@ type InstanceRecord struct {
2222

2323
func (r *InstanceRecord) MarshalJSON() ([]byte, error) {
2424
type Alias InstanceRecord
25-
return json.Marshal(&struct {
25+
data := &struct {
2626
*Alias
27-
Expiry int64 `json:"stamp"`
27+
Expiry string `json:"expiry"`
2828
}{
2929
Alias: (*Alias)(r),
30-
Expiry: r.Expiry.Unix(),
31-
})
30+
Expiry: r.Expiry.Format(time.TimeOnly) + " UTC",
31+
}
32+
if r.Expiry.Before(time.Now()) {
33+
data.Expiry = "Expired"
34+
}
35+
return json.Marshal(data)
3236
}
3337

3438
func (in *Instancer) InitDB(file string) error {

src/instancer.go

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func InitInstancer() (*Instancer, error) {
6363
if err != nil {
6464
log.Fatal().Err(err).Msg("could not load config")
6565
}
66-
log.Info().Int("count", len(in.config.Challenges)).Msg("read challenges from config")
66+
//log.Info().Int("count", len(in.config.Challenges)).Msg("read challenges from config")
6767
log.Debug().Str("value", in.config.ListenAddr).Msg("read listenAddr from config")
6868

6969
/* in.challengeObjs, err = UnmarshalChallenges(in.config.Challenges)
@@ -75,36 +75,22 @@ func InitInstancer() (*Instancer, error) {
7575
}
7676
log.Info().Int("count", len(in.challengeObjs)).Msg("parsed challenges") */
7777
// Parse templates
78-
in.challengeTmpls = make(map[string]*template.Template, len(in.config.Challenges))
79-
for k, v := range in.config.Challenges {
80-
tmpl, err := template.New("challenge").Parse(v)
81-
if err != nil {
82-
log.Error().Err(err).Str("challenge", k).Msg("could not parse a challenge template")
83-
continue
84-
}
85-
in.challengeTmpls[k] = tmpl
86-
}
87-
78+
/* in.challengeTmpls = make(map[string]*template.Template, len(in.config.Challenges))
79+
for k, v := range in.config.Challenges {
80+
tmpl, err := template.New("challenge").Parse(v)
81+
if err != nil {
82+
log.Error().Err(err).Str("challenge", k).Msg("could not parse a challenge template")
83+
continue
84+
}
85+
in.challengeTmpls[k] = tmpl
86+
} */
8887
in.k8sConfig, err = rest.InClusterConfig()
8988
if err != nil {
9089
log.Fatal().Err(err).Msg("could not create kube-api client config")
9190
}
9291
rest.SetKubernetesDefaults(in.k8sConfig)
9392
log.Debug().Str("config", fmt.Sprintf("%+v", in.k8sConfig)).Msg("loaded kube-api client config")
94-
95-
// Test CRDs
96-
log.Debug().Msg("querying CRDs")
97-
crdChallObjs, err := in.QueryInstancedChallenges("challenges")
98-
if err != nil {
99-
log.Debug().Err(err).Msg("error retrieving challenge definitions from CRDs")
100-
} else {
101-
for k, o := range crdChallObjs {
102-
log.Debug().Str("challenge", k).Msg("parsed challenge from CRD")
103-
for _, v := range o {
104-
log.Debug().Str("kind", v.GetKind()).Str("name", v.GetName()).Str("challenge", k).Msg("parsed resource")
105-
}
106-
}
107-
}
93+
in.LoadCRDs()
10894

10995
err = in.InitDB("/data/instancer.db")
11096
if err != nil {
@@ -115,6 +101,21 @@ func InitInstancer() (*Instancer, error) {
115101
return &in, nil
116102
}
117103

104+
func (in *Instancer) LoadCRDs() {
105+
log := in.log
106+
// Test CRDs
107+
log.Debug().Msg("querying CRDs")
108+
crdChallObjs, err := in.QueryInstancedChallenges("challenges")
109+
if err != nil {
110+
log.Debug().Err(err).Msg("error retrieving challenge definitions from CRDs")
111+
}
112+
for k := range crdChallObjs {
113+
log.Info().Str("challenge", k).Msg("parsed challenge template")
114+
}
115+
log.Info().Int("count", len(crdChallObjs)).Msg("parsed challenges")
116+
in.challengeTmpls = crdChallObjs
117+
}
118+
118119
func (in *Instancer) DestoryExpiredInstances() {
119120
log := in.log.With().Str("component", "instanced").Logger()
120121
instances, err := in.ReadInstanceRecords()

src/k8sclient.go

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"strings"
7+
"text/template"
78

89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -150,7 +151,7 @@ func (in *Instancer) GetObjectResource(unstructObj *unstructured.Unstructured) (
150151
return mapping.Resource, nil
151152
}
152153

153-
func (in *Instancer) QueryInstancedChallenges(namespace string) (map[string][]unstructured.Unstructured, error) {
154+
func (in *Instancer) QueryInstancedChallenges(namespace string) (map[string]*template.Template, error) {
154155
resource := schema.GroupVersionResource{
155156
Group: "k8s.maplebacon.org",
156157
Version: "unstable",
@@ -167,25 +168,21 @@ func (in *Instancer) QueryInstancedChallenges(namespace string) (map[string][]un
167168
return nil, err
168169
}
169170

170-
ret := make(map[string][]unstructured.Unstructured)
171+
ret := make(map[string]*template.Template)
171172

172173
for _, c := range chalList.Items {
173-
resources, found, err := unstructured.NestedSlice(c.Object, "spec", "resources")
174+
tmplStr, found, err := unstructured.NestedString(c.Object, "spec", "challengeTemplate")
174175
if err != nil || !found {
175-
fmt.Printf("resources not found for challenge crd %v: error=%v", c.GetName(), err)
176+
fmt.Printf("template not found for challenge crd %v: error=%v", c.GetName(), err)
176177
continue
177178
}
178179

179-
res := make([]unstructured.Unstructured, 0)
180-
181-
for _, r := range resources {
182-
obj, ok := r.(map[string]interface{})
183-
if !ok {
184-
fmt.Printf("could not parse object")
185-
}
186-
res = append(res, unstructured.Unstructured{Object: obj})
180+
tmpl, err := template.New("challenge").Parse(tmplStr)
181+
if err != nil {
182+
in.log.Error().Err(err).Str("challenge", c.GetName()).Msg("could not parse a challenge template")
183+
continue
187184
}
188-
ret[c.GetName()] = res
185+
ret[c.GetName()] = tmpl
189186
}
190187
return ret, nil
191188
}

src/webserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (in *Instancer) handleInstanceCreate(c echo.Context) error {
5858
return c.JSON(http.StatusInternalServerError, "challenge deploy failed: contact admin")
5959
}
6060
c.Logger().Info("processed request to provision new instance")
61-
return c.JSON(http.StatusAccepted, InstancesResponse{"created", chalName, rec.Id, fmt.Sprintf("http://%v.%v.ctf.maplebacon.org", rec.UUID, chalName)})
61+
return c.JSON(http.StatusAccepted, InstancesResponse{"created", chalName, rec.Id, fmt.Sprintf("https://%v.%v.ctf.maplebacon.org", rec.UUID, chalName)})
6262
}
6363

6464
func (in *Instancer) handleInstanceDelete(c echo.Context) error {

0 commit comments

Comments
 (0)