blob: 5a0761b61a4e31d69aab1b7eb5bdd33005dc267d [file] [log] [blame]
ktimoney3570d5a2022-05-24 13:54:55 +01001// -
2// ========================LICENSE_START=================================
3// O-RAN-SC
4// %%
5// Copyright (C) 2022: Nordix Foundation
6// %%
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10//
11// http://www.apache.org/licenses/LICENSE-2.0
12//
13// Unless required by applicable law or agreed to in writing, software
14// distributed under the License is distributed on an "AS IS" BASIS,
15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16// See the License for the specific language governing permissions and
17// limitations under the License.
18// ========================LICENSE_END===================================
19//
20
ktimoney6be05292022-03-02 12:53:14 +000021package main
22
23import (
24 "bytes"
25 "context"
26 "fmt"
27 netv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
28 secv1beta1 "istio.io/client-go/pkg/apis/security/v1beta1"
29 versioned "istio.io/client-go/pkg/clientset/versioned"
30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 k8Yaml "k8s.io/apimachinery/pkg/util/yaml"
32 "k8s.io/client-go/rest"
33 clientcmd "k8s.io/client-go/tools/clientcmd"
34 "log"
35 "net/http"
36 "os"
37 "path/filepath"
ktimoneyf27b5132022-03-07 16:48:47 +000038 "strings"
ktimoney6be05292022-03-02 12:53:14 +000039)
40
41const (
42 NAMESPACE = "istio-nonrtric"
43)
44
ktimoneyf27b5132022-03-07 16:48:47 +000045var gatewayManifest = `
ktimoney6be05292022-03-02 12:53:14 +000046apiVersion: networking.istio.io/v1beta1
47kind: Gateway
48metadata:
ktimoneyf27b5132022-03-07 16:48:47 +000049 name: nonrtric-istio-RAPP-NAME-gateway
50 namespace: RAPP-NS
ktimoney6be05292022-03-02 12:53:14 +000051spec:
52 selector:
53 istio: ingressgateway # use Istio gateway implementation
54 servers:
55 - port:
56 number: 80
57 name: http
58 protocol: HTTP
59 hosts:
60 - "*"
61`
62
ktimoneyf27b5132022-03-07 16:48:47 +000063var virtualServiceManifest = `
ktimoney6be05292022-03-02 12:53:14 +000064apiVersion: networking.istio.io/v1beta1
65kind: VirtualService
66metadata:
ktimoneyf27b5132022-03-07 16:48:47 +000067 name: nonrtric-istio-RAPP-NAME-vs
68 namespace: RAPP-NS
ktimoney6be05292022-03-02 12:53:14 +000069spec:
70 hosts:
71 - "*"
72 gateways:
ktimoneyf27b5132022-03-07 16:48:47 +000073 - nonrtric-istio-RAPP-NAME-gateway
ktimoney6be05292022-03-02 12:53:14 +000074 http:
ktimoneyf27b5132022-03-07 16:48:47 +000075 - name: "RAPP-NAME-routes"
ktimoney6be05292022-03-02 12:53:14 +000076 match:
77 - uri:
ktimoneyf27b5132022-03-07 16:48:47 +000078 prefix: "/RAPP-NAME"
ktimoney6be05292022-03-02 12:53:14 +000079 route:
80 - destination:
81 port:
82 number: 80
ktimoneyf27b5132022-03-07 16:48:47 +000083 host: RAPP-NAME.RAPP-NS.svc.cluster.local
ktimoney6be05292022-03-02 12:53:14 +000084`
85
ktimoneyf27b5132022-03-07 16:48:47 +000086var requestAuthenticationManifest = `
ktimoney6be05292022-03-02 12:53:14 +000087apiVersion: security.istio.io/v1beta1
88kind: RequestAuthentication
89metadata:
ktimoneyf27b5132022-03-07 16:48:47 +000090 name: "jwt-RAPP-NAME"
91 namespace: RAPP-NS
ktimoney6be05292022-03-02 12:53:14 +000092spec:
93 selector:
94 matchLabels:
ktimoneyf27b5132022-03-07 16:48:47 +000095 app.kubernetes.io/instance: RAPP-NAME
ktimoney6be05292022-03-02 12:53:14 +000096 jwtRules:
ktimoneyf27b5132022-03-07 16:48:47 +000097 - issuer: "http://192.168.49.2:31560/auth/realms/REALM-NAME"
98 jwksUri: "http://192.168.49.2:31560/auth/realms/REALM-NAME/protocol/openid-connect/certs"
99 - issuer: "http://keycloak.default:8080/auth/realms/REALM-NAME"
100 jwksUri: "http://keycloak.default:8080/auth/realms/REALM-NAME/protocol/openid-connect/certs"
ktimoney8ead72a2022-04-12 15:10:10 +0100101 - issuer: "https://192.168.49.2:31561/auth/realms/REALM-NAME"
102 jwksUri: "https://192.168.49.2:31561/auth/realms/REALM-NAME/protocol/openid-connect/certs"
103 - issuer: "https://keycloak.default:8443/auth/realms/REALM-NAME"
104 jwksUri: "https://keycloak.default:8443/auth/realms/REALM-NAME/protocol/openid-connect/certs"
105 - issuer: "https://keycloak.est.tech:443/auth/realms/REALM-NAME"
106 jwksUri: "https://keycloak.default:8443/auth/realms/REALM-NAME/protocol/openid-connect/certs"
107 - issuer: "http://istio-ingressgateway.istio-system:80/auth/realms/REALM-NAME"
108 jwksUri: "http://keycloak.default:8080/auth/realms/REALM-NAME/protocol/openid-connect/certs"
ktimoney6be05292022-03-02 12:53:14 +0000109`
110
ktimoneyf27b5132022-03-07 16:48:47 +0000111var authorizationPolicyManifest = `
ktimoney6be05292022-03-02 12:53:14 +0000112apiVersion: "security.istio.io/v1beta1"
113kind: "AuthorizationPolicy"
114metadata:
ktimoneyf27b5132022-03-07 16:48:47 +0000115 name: "RAPP-NAME-policy"
116 namespace: RAPP-NS
ktimoney6be05292022-03-02 12:53:14 +0000117spec:
118 selector:
119 matchLabels:
ktimoneyf27b5132022-03-07 16:48:47 +0000120 app.kubernetes.io/instance: RAPP-NAME
ktimoney6be05292022-03-02 12:53:14 +0000121 action: ALLOW
122 rules:
123 - from:
124 - source:
ktimoney8ead72a2022-04-12 15:10:10 +0100125 requestPrincipals: ["http://192.168.49.2:31560/auth/realms/REALM-NAME/", "http://keycloak.default:8080/auth/realms/REALM-NAME/", "https://192.168.49.2:31561/auth/realms/REALM-NAME/", "https://keycloak.default:8443/auth/realms/REALM-NAME/", "https://keycloak.est.tech:443/auth/realms/REALM-NAME/", "http://istio-ingressgateway.istio-system:80/auth/realms/REALM-NAME/"]
ktimoney6be05292022-03-02 12:53:14 +0000126 - to:
127 - operation:
ktimoneyf27b5132022-03-07 16:48:47 +0000128 methods: ["METHOD-NAME"]
ktimoney8ead72a2022-04-12 15:10:10 +0100129 paths: ["/RAPP-NAME"]
ktimoney6be05292022-03-02 12:53:14 +0000130 when:
131 - key: request.auth.claims[clientRole]
ktimoneyf27b5132022-03-07 16:48:47 +0000132 values: ["ROLE-NAME"]
ktimoney6be05292022-03-02 12:53:14 +0000133`
134
135func connectToK8s() *versioned.Clientset {
136 config, err := rest.InClusterConfig()
137 if err != nil {
138 // fallback to kubeconfig
139 home, exists := os.LookupEnv("HOME")
140 if !exists {
141 home = "/root"
142 }
143
144 kubeconfig := filepath.Join(home, ".kube", "config")
145 if envvar := os.Getenv("KUBECONFIG"); len(envvar) > 0 {
146 kubeconfig = envvar
147 }
148 config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
149 if err != nil {
150 log.Fatalln("failed to create K8s config")
151 }
152 }
153
154 ic, err := versioned.NewForConfig(config)
155 if err != nil {
156 log.Fatalf("Failed to create istio client: %s", err)
157 }
158
159 return ic
160}
161
ktimoneyf27b5132022-03-07 16:48:47 +0000162func createGateway(clientset *versioned.Clientset, appName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000163 gtClient := clientset.NetworkingV1beta1().Gateways(NAMESPACE)
ktimoney8ead72a2022-04-12 15:10:10 +0100164 manifest := strings.Replace(gatewayManifest, "RAPP-NAME", appName, -1)
165 manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000166
167 gt := &netv1beta1.Gateway{}
ktimoney8ead72a2022-04-12 15:10:10 +0100168 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
ktimoney6be05292022-03-02 12:53:14 +0000169
170 if err := dec.Decode(&gt); err != nil {
171 return "", err
172 }
173
174 result, err := gtClient.Create(context.TODO(), gt, metav1.CreateOptions{})
175
176 if err != nil {
177 return "", err
178 }
179
180 fmt.Printf("Create Gateway %s \n", result.GetName())
181 return result.GetName(), nil
182}
183
ktimoneyf27b5132022-03-07 16:48:47 +0000184func createVirtualService(clientset *versioned.Clientset, appName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000185 vsClient := clientset.NetworkingV1beta1().VirtualServices(NAMESPACE)
ktimoney8ead72a2022-04-12 15:10:10 +0100186 manifest := strings.Replace(virtualServiceManifest, "RAPP-NAME", appName, -1)
187 manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000188
189 vs := &netv1beta1.VirtualService{}
ktimoney8ead72a2022-04-12 15:10:10 +0100190 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
ktimoney6be05292022-03-02 12:53:14 +0000191
192 if err := dec.Decode(&vs); err != nil {
193 return "", err
194 }
195
196 result, err := vsClient.Create(context.TODO(), vs, metav1.CreateOptions{})
197
198 if err != nil {
199 return "", err
200 }
201
202 fmt.Printf("Create Virtual Service %s \n", result.GetName())
203 return result.GetName(), nil
204}
205
ktimoneyf27b5132022-03-07 16:48:47 +0000206func createRequestAuthentication(clientset *versioned.Clientset, appName, realmName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000207 raClient := clientset.SecurityV1beta1().RequestAuthentications(NAMESPACE)
ktimoney8ead72a2022-04-12 15:10:10 +0100208 manifest := strings.Replace(requestAuthenticationManifest, "RAPP-NAME", appName, -1)
209 manifest = strings.Replace(manifest, "REALM-NAME", realmName, -1)
210 manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000211
212 ra := &secv1beta1.RequestAuthentication{}
ktimoney8ead72a2022-04-12 15:10:10 +0100213 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
ktimoney6be05292022-03-02 12:53:14 +0000214
215 if err := dec.Decode(&ra); err != nil {
216 return "", err
217 }
218
219 result, err := raClient.Create(context.TODO(), ra, metav1.CreateOptions{})
220
221 if err != nil {
222 return "", err
223 }
224
225 fmt.Printf("Create Request Authentication %s \n", result.GetName())
226 return result.GetName(), nil
227}
228
ktimoneyf27b5132022-03-07 16:48:47 +0000229func createAuthorizationPolicy(clientset *versioned.Clientset, appName, realmName, roleName, methodName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000230 apClient := clientset.SecurityV1beta1().AuthorizationPolicies(NAMESPACE)
ktimoney8ead72a2022-04-12 15:10:10 +0100231 manifest := strings.Replace(authorizationPolicyManifest, "RAPP-NAME", appName, -1)
232 manifest = strings.Replace(manifest, "REALM-NAME", realmName, -1)
233 manifest = strings.Replace(manifest, "ROLE-NAME", roleName, -1)
234 manifest = strings.Replace(manifest, "METHOD-NAME", methodName, -1)
235 manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000236
237 ap := &secv1beta1.AuthorizationPolicy{}
ktimoney8ead72a2022-04-12 15:10:10 +0100238 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
ktimoney6be05292022-03-02 12:53:14 +0000239
240 if err := dec.Decode(&ap); err != nil {
241 return "", err
242 }
243
244 result, err := apClient.Create(context.TODO(), ap, metav1.CreateOptions{})
245
246 if err != nil {
247 return "", err
248 }
249
250 fmt.Printf("Create Authorization Policy %s \n", result.GetName())
251 return result.GetName(), nil
252}
253
ktimoneyf27b5132022-03-07 16:48:47 +0000254func removeGateway(clientset *versioned.Clientset, appName string) {
255 gtClient := clientset.NetworkingV1beta1().Gateways(NAMESPACE)
256 err := gtClient.Delete(context.TODO(), "nonrtric-istio-"+appName+"-gateway", metav1.DeleteOptions{})
257 if err != nil {
258 fmt.Println(err)
259 } else {
260 fmt.Println("Deleted Gateway nonrtric-istio-" + appName + "-gateway")
261 }
262}
ktimoney6be05292022-03-02 12:53:14 +0000263
ktimoneyf27b5132022-03-07 16:48:47 +0000264func removeVirtualService(clientset *versioned.Clientset, appName string) {
265 vsClient := clientset.NetworkingV1beta1().VirtualServices(NAMESPACE)
266 err := vsClient.Delete(context.TODO(), "nonrtric-istio-"+appName+"-vs", metav1.DeleteOptions{})
267 if err != nil {
268 fmt.Println(err)
269 } else {
270 fmt.Println("Deleted VirtualServices nonrtric-istio-" + appName + "-vs")
271 }
272}
273
274func removeRequestAuthentication(clientset *versioned.Clientset, appName string) {
275 raClient := clientset.SecurityV1beta1().RequestAuthentications(NAMESPACE)
276 err := raClient.Delete(context.TODO(), "jwt-"+appName, metav1.DeleteOptions{})
277 if err != nil {
278 fmt.Println(err)
279 } else {
280 fmt.Println("Deleted RequestAuthentication jwt-" + appName)
281 }
282}
283
284func removeAuthorizationPolicy(clientset *versioned.Clientset, appName string) {
285 apClient := clientset.SecurityV1beta1().AuthorizationPolicies(NAMESPACE)
286 err := apClient.Delete(context.TODO(), appName+"-policy", metav1.DeleteOptions{})
287 if err != nil {
288 fmt.Println(err)
289 } else {
290 fmt.Println("Deleted AuthorizationPolicy " + appName + "-policy")
291 }
292}
293
294func createIstioPolicy(res http.ResponseWriter, req *http.Request) {
295 query := req.URL.Query()
296 realmName := query.Get("realm")
297 appName := query.Get("name")
298 roleName := query.Get("role")
299 methodName := query.Get("method")
ktimoney6be05292022-03-02 12:53:14 +0000300 var msg string
301 clientset := connectToK8s()
ktimoneyf27b5132022-03-07 16:48:47 +0000302 _, err := createGateway(clientset, appName)
ktimoney6be05292022-03-02 12:53:14 +0000303 if err != nil {
304 msg = err.Error()
305 fmt.Println(err.Error())
306 } else {
ktimoneyf27b5132022-03-07 16:48:47 +0000307 _, err := createVirtualService(clientset, appName)
ktimoney6be05292022-03-02 12:53:14 +0000308 if err != nil {
309 msg = err.Error()
310 fmt.Println(err.Error())
311 } else {
ktimoneyf27b5132022-03-07 16:48:47 +0000312 _, err := createRequestAuthentication(clientset, appName, realmName)
ktimoney6be05292022-03-02 12:53:14 +0000313 if err != nil {
314 msg = err.Error()
315 fmt.Println(err.Error())
316 } else {
ktimoneyf27b5132022-03-07 16:48:47 +0000317 _, err := createAuthorizationPolicy(clientset, appName, realmName, roleName, methodName)
ktimoney6be05292022-03-02 12:53:14 +0000318 if err != nil {
319 msg = err.Error()
320 fmt.Println(err.Error())
321 } else {
322 msg = "Istio rapp security setup successfully"
323 }
324 }
325 }
326 }
327
328 // create response binary data
329 data := []byte(msg) // slice of bytes
330 // write `data` to response
331 res.Write(data)
332}
333
ktimoneyf27b5132022-03-07 16:48:47 +0000334func removeIstioPolicy(res http.ResponseWriter, req *http.Request) {
335 query := req.URL.Query()
336 appName := query.Get("name")
337 clientset := connectToK8s()
338 removeAuthorizationPolicy(clientset, appName)
339 removeRequestAuthentication(clientset, appName)
340 removeVirtualService(clientset, appName)
341 removeGateway(clientset, appName)
342}
343
ktimoney6be05292022-03-02 12:53:14 +0000344func main() {
ktimoneyf27b5132022-03-07 16:48:47 +0000345 createIstioHandler := http.HandlerFunc(createIstioPolicy)
346 http.Handle("/create", createIstioHandler)
347 removeIstioHandler := http.HandlerFunc(removeIstioPolicy)
348 http.Handle("/remove", removeIstioHandler)
349 http.ListenAndServe(":9000", nil)
ktimoney6be05292022-03-02 12:53:14 +0000350}