blob: 04189ce53940e7ef939bcc05bf3c2a8c227a0f35 [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"
ktimoney6be05292022-03-02 12:53:14 +000081`
82
ktimoneyf27b5132022-03-07 16:48:47 +000083var authorizationPolicyManifest = `
ktimoney6be05292022-03-02 12:53:14 +000084apiVersion: "security.istio.io/v1beta1"
85kind: "AuthorizationPolicy"
86metadata:
ktimoneyf27b5132022-03-07 16:48:47 +000087 name: "RAPP-NAME-policy"
88 namespace: RAPP-NS
ktimoney6be05292022-03-02 12:53:14 +000089spec:
90 selector:
91 matchLabels:
ktimoneyf27b5132022-03-07 16:48:47 +000092 app.kubernetes.io/instance: RAPP-NAME
ktimoney6be05292022-03-02 12:53:14 +000093 action: ALLOW
94 rules:
95 - from:
96 - source:
ktimoneyf27b5132022-03-07 16:48:47 +000097 requestPrincipals: ["http://192.168.49.2:31560/auth/realms/REALM-NAME/", "http://keycloak.default:8080/auth/realms/REALM-NAME/"]
ktimoney6be05292022-03-02 12:53:14 +000098 - to:
99 - operation:
ktimoneyf27b5132022-03-07 16:48:47 +0000100 methods: ["METHOD-NAME"]
101 paths: ["/RAPP-NAME*"]
ktimoney6be05292022-03-02 12:53:14 +0000102 when:
103 - key: request.auth.claims[clientRole]
ktimoneyf27b5132022-03-07 16:48:47 +0000104 values: ["ROLE-NAME"]
ktimoney6be05292022-03-02 12:53:14 +0000105`
106
107func connectToK8s() *versioned.Clientset {
108 config, err := rest.InClusterConfig()
109 if err != nil {
110 // fallback to kubeconfig
111 home, exists := os.LookupEnv("HOME")
112 if !exists {
113 home = "/root"
114 }
115
116 kubeconfig := filepath.Join(home, ".kube", "config")
117 if envvar := os.Getenv("KUBECONFIG"); len(envvar) > 0 {
118 kubeconfig = envvar
119 }
120 config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
121 if err != nil {
122 log.Fatalln("failed to create K8s config")
123 }
124 }
125
126 ic, err := versioned.NewForConfig(config)
127 if err != nil {
128 log.Fatalf("Failed to create istio client: %s", err)
129 }
130
131 return ic
132}
133
ktimoneyf27b5132022-03-07 16:48:47 +0000134func createGateway(clientset *versioned.Clientset, appName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000135 gtClient := clientset.NetworkingV1beta1().Gateways(NAMESPACE)
ktimoneyf27b5132022-03-07 16:48:47 +0000136 gatewayManifest = strings.Replace(gatewayManifest, "RAPP-NAME", appName, -1)
137 gatewayManifest = strings.Replace(gatewayManifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000138
139 gt := &netv1beta1.Gateway{}
140 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(gatewayManifest)), 1000)
141
142 if err := dec.Decode(&gt); err != nil {
143 return "", err
144 }
145
146 result, err := gtClient.Create(context.TODO(), gt, metav1.CreateOptions{})
147
148 if err != nil {
149 return "", err
150 }
151
152 fmt.Printf("Create Gateway %s \n", result.GetName())
153 return result.GetName(), nil
154}
155
ktimoneyf27b5132022-03-07 16:48:47 +0000156func createVirtualService(clientset *versioned.Clientset, appName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000157 vsClient := clientset.NetworkingV1beta1().VirtualServices(NAMESPACE)
ktimoneyf27b5132022-03-07 16:48:47 +0000158 virtualServiceManifest = strings.Replace(virtualServiceManifest, "RAPP-NAME", appName, -1)
159 virtualServiceManifest = strings.Replace(virtualServiceManifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000160
161 vs := &netv1beta1.VirtualService{}
162 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(virtualServiceManifest)), 1000)
163
164 if err := dec.Decode(&vs); err != nil {
165 return "", err
166 }
167
168 result, err := vsClient.Create(context.TODO(), vs, metav1.CreateOptions{})
169
170 if err != nil {
171 return "", err
172 }
173
174 fmt.Printf("Create Virtual Service %s \n", result.GetName())
175 return result.GetName(), nil
176}
177
ktimoneyf27b5132022-03-07 16:48:47 +0000178func createRequestAuthentication(clientset *versioned.Clientset, appName, realmName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000179 raClient := clientset.SecurityV1beta1().RequestAuthentications(NAMESPACE)
ktimoneyf27b5132022-03-07 16:48:47 +0000180 requestAuthenticationManifest = strings.Replace(requestAuthenticationManifest, "RAPP-NAME", appName, -1)
181 requestAuthenticationManifest = strings.Replace(requestAuthenticationManifest, "REALM-NAME", realmName, -1)
182 requestAuthenticationManifest = strings.Replace(requestAuthenticationManifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000183
184 ra := &secv1beta1.RequestAuthentication{}
185 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(requestAuthenticationManifest)), 1000)
186
187 if err := dec.Decode(&ra); err != nil {
188 return "", err
189 }
190
191 result, err := raClient.Create(context.TODO(), ra, metav1.CreateOptions{})
192
193 if err != nil {
194 return "", err
195 }
196
197 fmt.Printf("Create Request Authentication %s \n", result.GetName())
198 return result.GetName(), nil
199}
200
ktimoneyf27b5132022-03-07 16:48:47 +0000201func createAuthorizationPolicy(clientset *versioned.Clientset, appName, realmName, roleName, methodName string) (string, error) {
ktimoney6be05292022-03-02 12:53:14 +0000202 apClient := clientset.SecurityV1beta1().AuthorizationPolicies(NAMESPACE)
ktimoneyf27b5132022-03-07 16:48:47 +0000203 authorizationPolicyManifest = strings.Replace(authorizationPolicyManifest, "RAPP-NAME", appName, -1)
204 authorizationPolicyManifest = strings.Replace(authorizationPolicyManifest, "REALM-NAME", realmName, -1)
205 authorizationPolicyManifest = strings.Replace(authorizationPolicyManifest, "ROLE-NAME", roleName, -1)
206 authorizationPolicyManifest = strings.Replace(authorizationPolicyManifest, "METHOD-NAME", methodName, -1)
207 authorizationPolicyManifest = strings.Replace(authorizationPolicyManifest, "RAPP-NS", NAMESPACE, -1)
ktimoney6be05292022-03-02 12:53:14 +0000208
209 ap := &secv1beta1.AuthorizationPolicy{}
210 dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(authorizationPolicyManifest)), 1000)
211
212 if err := dec.Decode(&ap); err != nil {
213 return "", err
214 }
215
216 result, err := apClient.Create(context.TODO(), ap, metav1.CreateOptions{})
217
218 if err != nil {
219 return "", err
220 }
221
222 fmt.Printf("Create Authorization Policy %s \n", result.GetName())
223 return result.GetName(), nil
224}
225
ktimoneyf27b5132022-03-07 16:48:47 +0000226func removeGateway(clientset *versioned.Clientset, appName string) {
227 gtClient := clientset.NetworkingV1beta1().Gateways(NAMESPACE)
228 err := gtClient.Delete(context.TODO(), "nonrtric-istio-"+appName+"-gateway", metav1.DeleteOptions{})
229 if err != nil {
230 fmt.Println(err)
231 } else {
232 fmt.Println("Deleted Gateway nonrtric-istio-" + appName + "-gateway")
233 }
234}
ktimoney6be05292022-03-02 12:53:14 +0000235
ktimoneyf27b5132022-03-07 16:48:47 +0000236func removeVirtualService(clientset *versioned.Clientset, appName string) {
237 vsClient := clientset.NetworkingV1beta1().VirtualServices(NAMESPACE)
238 err := vsClient.Delete(context.TODO(), "nonrtric-istio-"+appName+"-vs", metav1.DeleteOptions{})
239 if err != nil {
240 fmt.Println(err)
241 } else {
242 fmt.Println("Deleted VirtualServices nonrtric-istio-" + appName + "-vs")
243 }
244}
245
246func removeRequestAuthentication(clientset *versioned.Clientset, appName string) {
247 raClient := clientset.SecurityV1beta1().RequestAuthentications(NAMESPACE)
248 err := raClient.Delete(context.TODO(), "jwt-"+appName, metav1.DeleteOptions{})
249 if err != nil {
250 fmt.Println(err)
251 } else {
252 fmt.Println("Deleted RequestAuthentication jwt-" + appName)
253 }
254}
255
256func removeAuthorizationPolicy(clientset *versioned.Clientset, appName string) {
257 apClient := clientset.SecurityV1beta1().AuthorizationPolicies(NAMESPACE)
258 err := apClient.Delete(context.TODO(), appName+"-policy", metav1.DeleteOptions{})
259 if err != nil {
260 fmt.Println(err)
261 } else {
262 fmt.Println("Deleted AuthorizationPolicy " + appName + "-policy")
263 }
264}
265
266func createIstioPolicy(res http.ResponseWriter, req *http.Request) {
267 query := req.URL.Query()
268 realmName := query.Get("realm")
269 appName := query.Get("name")
270 roleName := query.Get("role")
271 methodName := query.Get("method")
ktimoney6be05292022-03-02 12:53:14 +0000272 var msg string
273 clientset := connectToK8s()
ktimoneyf27b5132022-03-07 16:48:47 +0000274 _, err := createGateway(clientset, appName)
ktimoney6be05292022-03-02 12:53:14 +0000275 if err != nil {
276 msg = err.Error()
277 fmt.Println(err.Error())
278 } else {
ktimoneyf27b5132022-03-07 16:48:47 +0000279 _, err := createVirtualService(clientset, appName)
ktimoney6be05292022-03-02 12:53:14 +0000280 if err != nil {
281 msg = err.Error()
282 fmt.Println(err.Error())
283 } else {
ktimoneyf27b5132022-03-07 16:48:47 +0000284 _, err := createRequestAuthentication(clientset, appName, realmName)
ktimoney6be05292022-03-02 12:53:14 +0000285 if err != nil {
286 msg = err.Error()
287 fmt.Println(err.Error())
288 } else {
ktimoneyf27b5132022-03-07 16:48:47 +0000289 _, err := createAuthorizationPolicy(clientset, appName, realmName, roleName, methodName)
ktimoney6be05292022-03-02 12:53:14 +0000290 if err != nil {
291 msg = err.Error()
292 fmt.Println(err.Error())
293 } else {
294 msg = "Istio rapp security setup successfully"
295 }
296 }
297 }
298 }
299
300 // create response binary data
301 data := []byte(msg) // slice of bytes
302 // write `data` to response
303 res.Write(data)
304}
305
ktimoneyf27b5132022-03-07 16:48:47 +0000306func removeIstioPolicy(res http.ResponseWriter, req *http.Request) {
307 query := req.URL.Query()
308 appName := query.Get("name")
309 clientset := connectToK8s()
310 removeAuthorizationPolicy(clientset, appName)
311 removeRequestAuthentication(clientset, appName)
312 removeVirtualService(clientset, appName)
313 removeGateway(clientset, appName)
314}
315
ktimoney6be05292022-03-02 12:53:14 +0000316func main() {
ktimoneyf27b5132022-03-07 16:48:47 +0000317 createIstioHandler := http.HandlerFunc(createIstioPolicy)
318 http.Handle("/create", createIstioHandler)
319 removeIstioHandler := http.HandlerFunc(removeIstioPolicy)
320 http.Handle("/remove", removeIstioHandler)
321 http.ListenAndServe(":9000", nil)
ktimoney6be05292022-03-02 12:53:14 +0000322}