blob: 93ed8bb90405ded6449fc78d879b49fc01c82093 [file] [log] [blame]
ktimoney6be05292022-03-02 12:53:14 +00001package main
2
3import (
4 "bytes"
5 "context"
6 "fmt"
7 netv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
8 secv1beta1 "istio.io/client-go/pkg/apis/security/v1beta1"
9 versioned "istio.io/client-go/pkg/clientset/versioned"
10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11 k8Yaml "k8s.io/apimachinery/pkg/util/yaml"
12 "k8s.io/client-go/rest"
13 clientcmd "k8s.io/client-go/tools/clientcmd"
14 "log"
15 "net/http"
16 "os"
17 "path/filepath"
ktimoneyf27b5132022-03-07 16:48:47 +000018 "strings"
ktimoney6be05292022-03-02 12:53:14 +000019)
20
21const (
22 NAMESPACE = "istio-nonrtric"
23)
24
ktimoneyf27b5132022-03-07 16:48:47 +000025var gatewayManifest = `
ktimoney6be05292022-03-02 12:53:14 +000026apiVersion: networking.istio.io/v1beta1
27kind: Gateway
28metadata:
ktimoneyf27b5132022-03-07 16:48:47 +000029 name: nonrtric-istio-RAPP-NAME-gateway
30 namespace: RAPP-NS
ktimoney6be05292022-03-02 12:53:14 +000031spec:
32 selector:
33 istio: ingressgateway # use Istio gateway implementation
34 servers:
35 - port:
36 number: 80
37 name: http
38 protocol: HTTP
39 hosts:
40 - "*"
41`
42
ktimoneyf27b5132022-03-07 16:48:47 +000043var virtualServiceManifest = `
ktimoney6be05292022-03-02 12:53:14 +000044apiVersion: networking.istio.io/v1beta1
45kind: VirtualService
46metadata:
ktimoneyf27b5132022-03-07 16:48:47 +000047 name: nonrtric-istio-RAPP-NAME-vs
48 namespace: RAPP-NS
ktimoney6be05292022-03-02 12:53:14 +000049spec:
50 hosts:
51 - "*"
52 gateways:
ktimoneyf27b5132022-03-07 16:48:47 +000053 - nonrtric-istio-RAPP-NAME-gateway
ktimoney6be05292022-03-02 12:53:14 +000054 http:
ktimoneyf27b5132022-03-07 16:48:47 +000055 - name: "RAPP-NAME-routes"
ktimoney6be05292022-03-02 12:53:14 +000056 match:
57 - uri:
ktimoneyf27b5132022-03-07 16:48:47 +000058 prefix: "/RAPP-NAME"
ktimoney6be05292022-03-02 12:53:14 +000059 route:
60 - destination:
61 port:
62 number: 80
ktimoneyf27b5132022-03-07 16:48:47 +000063 host: RAPP-NAME.RAPP-NS.svc.cluster.local
ktimoney6be05292022-03-02 12:53:14 +000064`
65
ktimoneyf27b5132022-03-07 16:48:47 +000066var requestAuthenticationManifest = `
ktimoney6be05292022-03-02 12:53:14 +000067apiVersion: security.istio.io/v1beta1
68kind: RequestAuthentication
69metadata:
ktimoneyf27b5132022-03-07 16:48:47 +000070 name: "jwt-RAPP-NAME"
71 namespace: RAPP-NS
ktimoney6be05292022-03-02 12:53:14 +000072spec:
73 selector:
74 matchLabels:
ktimoneyf27b5132022-03-07 16:48:47 +000075 app.kubernetes.io/instance: RAPP-NAME
ktimoney6be05292022-03-02 12:53:14 +000076 jwtRules:
ktimoneyf27b5132022-03-07 16:48:47 +000077 - issuer: "http://192.168.49.2:31560/auth/realms/REALM-NAME"
78 jwksUri: "http://192.168.49.2:31560/auth/realms/REALM-NAME/protocol/openid-connect/certs"
79 - issuer: "http://keycloak.default:8080/auth/realms/REALM-NAME"
80 jwksUri: "http://keycloak.default:8080/auth/realms/REALM-NAME/protocol/openid-connect/certs"
ktimoney8ead72a2022-04-12 15:10:10 +010081 - issuer: "https://192.168.49.2:31561/auth/realms/REALM-NAME"
82 jwksUri: "https://192.168.49.2:31561/auth/realms/REALM-NAME/protocol/openid-connect/certs"
83 - issuer: "https://keycloak.default:8443/auth/realms/REALM-NAME"
84 jwksUri: "https://keycloak.default:8443/auth/realms/REALM-NAME/protocol/openid-connect/certs"
85 - issuer: "https://keycloak.est.tech:443/auth/realms/REALM-NAME"
86 jwksUri: "https://keycloak.default:8443/auth/realms/REALM-NAME/protocol/openid-connect/certs"
87 - issuer: "http://istio-ingressgateway.istio-system:80/auth/realms/REALM-NAME"
88 jwksUri: "http://keycloak.default:8080/auth/realms/REALM-NAME/protocol/openid-connect/certs"
ktimoney6be05292022-03-02 12:53:14 +000089`
90
ktimoneyf27b5132022-03-07 16:48:47 +000091var authorizationPolicyManifest = `
ktimoney6be05292022-03-02 12:53:14 +000092apiVersion: "security.istio.io/v1beta1"
93kind: "AuthorizationPolicy"
94metadata:
ktimoneyf27b5132022-03-07 16:48:47 +000095 name: "RAPP-NAME-policy"
96 namespace: RAPP-NS
ktimoney6be05292022-03-02 12:53:14 +000097spec:
98 selector:
99 matchLabels:
ktimoneyf27b5132022-03-07 16:48:47 +0000100 app.kubernetes.io/instance: RAPP-NAME
ktimoney6be05292022-03-02 12:53:14 +0000101 action: ALLOW
102 rules:
103 - from:
104 - source:
ktimoney8ead72a2022-04-12 15:10:10 +0100105 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 +0000106 - to:
107 - operation:
ktimoneyf27b5132022-03-07 16:48:47 +0000108 methods: ["METHOD-NAME"]
ktimoney8ead72a2022-04-12 15:10:10 +0100109 paths: ["/RAPP-NAME"]
ktimoney6be05292022-03-02 12:53:14 +0000110 when:
111 - key: request.auth.claims[clientRole]
ktimoneyf27b5132022-03-07 16:48:47 +0000112 values: ["ROLE-NAME"]
ktimoney6be05292022-03-02 12:53:14 +0000113`
114
115func connectToK8s() *versioned.Clientset {
116 config, err := rest.InClusterConfig()
117 if err != nil {
118 // fallback to kubeconfig
119 home, exists := os.LookupEnv("HOME")
120 if !exists {
121 home = "/root"
122 }
123
124 kubeconfig := filepath.Join(home, ".kube", "config")
125 if envvar := os.Getenv("KUBECONFIG"); len(envvar) > 0 {
126 kubeconfig = envvar
127 }
128 config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
129 if err != nil {
130 log.Fatalln("failed to create K8s config")
131 }
132 }
133
134 ic, err := versioned.NewForConfig(config)
135 if err != nil {
136 log.Fatalf("Failed to create istio client: %s", err)
137 }
138
139 return ic
140}
141
ktimoneyf27b5132022-03-07 16:48:47 +0000142func createGateway(clientset *versioned.Clientset, appName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000143 gtClient := clientset.NetworkingV1beta1().Gateways(NAMESPACE)
ktimoney8ead72a2022-04-12 15:10:10 +0100144 manifest := strings.Replace(gatewayManifest, "RAPP-NAME", appName, -1)
145 manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000146
147 gt := &netv1beta1.Gateway{}
ktimoney8ead72a2022-04-12 15:10:10 +0100148 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
ktimoney6be05292022-03-02 12:53:14 +0000149
150 if err := dec.Decode(&gt); err != nil {
151 return "", err
152 }
153
154 result, err := gtClient.Create(context.TODO(), gt, metav1.CreateOptions{})
155
156 if err != nil {
157 return "", err
158 }
159
160 fmt.Printf("Create Gateway %s \n", result.GetName())
161 return result.GetName(), nil
162}
163
ktimoneyf27b5132022-03-07 16:48:47 +0000164func createVirtualService(clientset *versioned.Clientset, appName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000165 vsClient := clientset.NetworkingV1beta1().VirtualServices(NAMESPACE)
ktimoney8ead72a2022-04-12 15:10:10 +0100166 manifest := strings.Replace(virtualServiceManifest, "RAPP-NAME", appName, -1)
167 manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000168
169 vs := &netv1beta1.VirtualService{}
ktimoney8ead72a2022-04-12 15:10:10 +0100170 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
ktimoney6be05292022-03-02 12:53:14 +0000171
172 if err := dec.Decode(&vs); err != nil {
173 return "", err
174 }
175
176 result, err := vsClient.Create(context.TODO(), vs, metav1.CreateOptions{})
177
178 if err != nil {
179 return "", err
180 }
181
182 fmt.Printf("Create Virtual Service %s \n", result.GetName())
183 return result.GetName(), nil
184}
185
ktimoneyf27b5132022-03-07 16:48:47 +0000186func createRequestAuthentication(clientset *versioned.Clientset, appName, realmName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000187 raClient := clientset.SecurityV1beta1().RequestAuthentications(NAMESPACE)
ktimoney8ead72a2022-04-12 15:10:10 +0100188 manifest := strings.Replace(requestAuthenticationManifest, "RAPP-NAME", appName, -1)
189 manifest = strings.Replace(manifest, "REALM-NAME", realmName, -1)
190 manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000191
192 ra := &secv1beta1.RequestAuthentication{}
ktimoney8ead72a2022-04-12 15:10:10 +0100193 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
ktimoney6be05292022-03-02 12:53:14 +0000194
195 if err := dec.Decode(&ra); err != nil {
196 return "", err
197 }
198
199 result, err := raClient.Create(context.TODO(), ra, metav1.CreateOptions{})
200
201 if err != nil {
202 return "", err
203 }
204
205 fmt.Printf("Create Request Authentication %s \n", result.GetName())
206 return result.GetName(), nil
207}
208
ktimoneyf27b5132022-03-07 16:48:47 +0000209func createAuthorizationPolicy(clientset *versioned.Clientset, appName, realmName, roleName, methodName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000210 apClient := clientset.SecurityV1beta1().AuthorizationPolicies(NAMESPACE)
ktimoney8ead72a2022-04-12 15:10:10 +0100211 manifest := strings.Replace(authorizationPolicyManifest, "RAPP-NAME", appName, -1)
212 manifest = strings.Replace(manifest, "REALM-NAME", realmName, -1)
213 manifest = strings.Replace(manifest, "ROLE-NAME", roleName, -1)
214 manifest = strings.Replace(manifest, "METHOD-NAME", methodName, -1)
215 manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000216
217 ap := &secv1beta1.AuthorizationPolicy{}
ktimoney8ead72a2022-04-12 15:10:10 +0100218 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
ktimoney6be05292022-03-02 12:53:14 +0000219
220 if err := dec.Decode(&ap); err != nil {
221 return "", err
222 }
223
224 result, err := apClient.Create(context.TODO(), ap, metav1.CreateOptions{})
225
226 if err != nil {
227 return "", err
228 }
229
230 fmt.Printf("Create Authorization Policy %s \n", result.GetName())
231 return result.GetName(), nil
232}
233
ktimoneyf27b5132022-03-07 16:48:47 +0000234func removeGateway(clientset *versioned.Clientset, appName string) {
235 gtClient := clientset.NetworkingV1beta1().Gateways(NAMESPACE)
236 err := gtClient.Delete(context.TODO(), "nonrtric-istio-"+appName+"-gateway", metav1.DeleteOptions{})
237 if err != nil {
238 fmt.Println(err)
239 } else {
240 fmt.Println("Deleted Gateway nonrtric-istio-" + appName + "-gateway")
241 }
242}
ktimoney6be05292022-03-02 12:53:14 +0000243
ktimoneyf27b5132022-03-07 16:48:47 +0000244func removeVirtualService(clientset *versioned.Clientset, appName string) {
245 vsClient := clientset.NetworkingV1beta1().VirtualServices(NAMESPACE)
246 err := vsClient.Delete(context.TODO(), "nonrtric-istio-"+appName+"-vs", metav1.DeleteOptions{})
247 if err != nil {
248 fmt.Println(err)
249 } else {
250 fmt.Println("Deleted VirtualServices nonrtric-istio-" + appName + "-vs")
251 }
252}
253
254func removeRequestAuthentication(clientset *versioned.Clientset, appName string) {
255 raClient := clientset.SecurityV1beta1().RequestAuthentications(NAMESPACE)
256 err := raClient.Delete(context.TODO(), "jwt-"+appName, metav1.DeleteOptions{})
257 if err != nil {
258 fmt.Println(err)
259 } else {
260 fmt.Println("Deleted RequestAuthentication jwt-" + appName)
261 }
262}
263
264func removeAuthorizationPolicy(clientset *versioned.Clientset, appName string) {
265 apClient := clientset.SecurityV1beta1().AuthorizationPolicies(NAMESPACE)
266 err := apClient.Delete(context.TODO(), appName+"-policy", metav1.DeleteOptions{})
267 if err != nil {
268 fmt.Println(err)
269 } else {
270 fmt.Println("Deleted AuthorizationPolicy " + appName + "-policy")
271 }
272}
273
274func createIstioPolicy(res http.ResponseWriter, req *http.Request) {
275 query := req.URL.Query()
276 realmName := query.Get("realm")
277 appName := query.Get("name")
278 roleName := query.Get("role")
279 methodName := query.Get("method")
ktimoney6be05292022-03-02 12:53:14 +0000280 var msg string
281 clientset := connectToK8s()
ktimoneyf27b5132022-03-07 16:48:47 +0000282 _, err := createGateway(clientset, appName)
ktimoney6be05292022-03-02 12:53:14 +0000283 if err != nil {
284 msg = err.Error()
285 fmt.Println(err.Error())
286 } else {
ktimoneyf27b5132022-03-07 16:48:47 +0000287 _, err := createVirtualService(clientset, appName)
ktimoney6be05292022-03-02 12:53:14 +0000288 if err != nil {
289 msg = err.Error()
290 fmt.Println(err.Error())
291 } else {
ktimoneyf27b5132022-03-07 16:48:47 +0000292 _, err := createRequestAuthentication(clientset, appName, realmName)
ktimoney6be05292022-03-02 12:53:14 +0000293 if err != nil {
294 msg = err.Error()
295 fmt.Println(err.Error())
296 } else {
ktimoneyf27b5132022-03-07 16:48:47 +0000297 _, err := createAuthorizationPolicy(clientset, appName, realmName, roleName, methodName)
ktimoney6be05292022-03-02 12:53:14 +0000298 if err != nil {
299 msg = err.Error()
300 fmt.Println(err.Error())
301 } else {
302 msg = "Istio rapp security setup successfully"
303 }
304 }
305 }
306 }
307
308 // create response binary data
309 data := []byte(msg) // slice of bytes
310 // write `data` to response
311 res.Write(data)
312}
313
ktimoneyf27b5132022-03-07 16:48:47 +0000314func removeIstioPolicy(res http.ResponseWriter, req *http.Request) {
315 query := req.URL.Query()
316 appName := query.Get("name")
317 clientset := connectToK8s()
318 removeAuthorizationPolicy(clientset, appName)
319 removeRequestAuthentication(clientset, appName)
320 removeVirtualService(clientset, appName)
321 removeGateway(clientset, appName)
322}
323
ktimoney6be05292022-03-02 12:53:14 +0000324func main() {
ktimoneyf27b5132022-03-07 16:48:47 +0000325 createIstioHandler := http.HandlerFunc(createIstioPolicy)
326 http.Handle("/create", createIstioHandler)
327 removeIstioHandler := http.HandlerFunc(removeIstioPolicy)
328 http.Handle("/remove", removeIstioHandler)
329 http.ListenAndServe(":9000", nil)
ktimoney6be05292022-03-02 12:53:14 +0000330}