Add jwt-proxy functionality
[nonrtric.git] / service-exposure / rapps-istio-mgr.go
index 5a0761b..fb584bd 100644 (file)
@@ -17,7 +17,6 @@
 //   limitations under the License.
 //   ========================LICENSE_END===================================
 //
-
 package main
 
 import (
@@ -25,6 +24,7 @@ import (
        "context"
        "fmt"
        netv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
+       netv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
        secv1beta1 "istio.io/client-go/pkg/apis/security/v1beta1"
        versioned "istio.io/client-go/pkg/clientset/versioned"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -35,102 +35,27 @@ import (
        "net/http"
        "os"
        "path/filepath"
-       "strings"
+       "text/template"
 )
 
 const (
        NAMESPACE = "istio-nonrtric"
 )
 
-var gatewayManifest = `
-apiVersion: networking.istio.io/v1beta1
-kind: Gateway
-metadata:
-  name: nonrtric-istio-RAPP-NAME-gateway
-  namespace: RAPP-NS 
-spec:
-  selector:
-    istio: ingressgateway # use Istio gateway implementation
-  servers:
-  - port:
-      number: 80
-      name: http
-      protocol: HTTP
-    hosts:
-    - "*"
-`
-
-var virtualServiceManifest = `
-apiVersion: networking.istio.io/v1beta1
-kind: VirtualService
-metadata:
-  name: nonrtric-istio-RAPP-NAME-vs
-  namespace: RAPP-NS 
-spec:
-  hosts:
-  - "*"
-  gateways:
-  - nonrtric-istio-RAPP-NAME-gateway
-  http:
-  - name: "RAPP-NAME-routes"
-    match:
-    - uri:
-        prefix: "/RAPP-NAME"
-    route:
-    - destination:
-        port:
-          number: 80
-        host: RAPP-NAME.RAPP-NS.svc.cluster.local
-`
-
-var requestAuthenticationManifest = `
-apiVersion: security.istio.io/v1beta1
-kind: RequestAuthentication
-metadata:
-  name: "jwt-RAPP-NAME"
-  namespace: RAPP-NS 
-spec:
-  selector:
-    matchLabels:
-      app.kubernetes.io/instance: RAPP-NAME
-  jwtRules:
-  - issuer: "http://192.168.49.2:31560/auth/realms/REALM-NAME"
-    jwksUri: "http://192.168.49.2:31560/auth/realms/REALM-NAME/protocol/openid-connect/certs"
-  - issuer: "http://keycloak.default:8080/auth/realms/REALM-NAME"
-    jwksUri: "http://keycloak.default:8080/auth/realms/REALM-NAME/protocol/openid-connect/certs"
-  - issuer: "https://192.168.49.2:31561/auth/realms/REALM-NAME"
-    jwksUri: "https://192.168.49.2:31561/auth/realms/REALM-NAME/protocol/openid-connect/certs"
-  - issuer: "https://keycloak.default:8443/auth/realms/REALM-NAME"
-    jwksUri: "https://keycloak.default:8443/auth/realms/REALM-NAME/protocol/openid-connect/certs"
-  - issuer: "https://keycloak.est.tech:443/auth/realms/REALM-NAME"
-    jwksUri: "https://keycloak.default:8443/auth/realms/REALM-NAME/protocol/openid-connect/certs"
-  - issuer: "http://istio-ingressgateway.istio-system:80/auth/realms/REALM-NAME"
-    jwksUri: "http://keycloak.default:8080/auth/realms/REALM-NAME/protocol/openid-connect/certs"
-`
-
-var authorizationPolicyManifest = `
-apiVersion: "security.istio.io/v1beta1"
-kind: "AuthorizationPolicy"
-metadata:
-  name: "RAPP-NAME-policy"
-  namespace: RAPP-NS 
-spec:
-  selector:
-    matchLabels:
-      app.kubernetes.io/instance: RAPP-NAME
-  action: ALLOW
-  rules:
-  - from:
-    - source:
-        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/"]
-  - to:
-    - operation:
-        methods: ["METHOD-NAME"]
-        paths: ["/RAPP-NAME"]
-    when:
-    - key: request.auth.claims[clientRole]
-      values: ["ROLE-NAME"]
-`
+type TemplateConfig struct {
+    Name string
+    Namespace string
+    Realm string
+    Client string
+    Authenticator string
+    Role string
+    Method string
+}
+
+var inputs TemplateConfig
+var appName string
+
+var config *template.Template
 
 func connectToK8s() *versioned.Clientset {
        config, err := rest.InClusterConfig()
@@ -159,13 +84,17 @@ func connectToK8s() *versioned.Clientset {
        return ic
 }
 
-func createGateway(clientset *versioned.Clientset, appName string) (string, error) {
+func createGateway(clientset *versioned.Clientset) (string, error) {
        gtClient := clientset.NetworkingV1beta1().Gateways(NAMESPACE)
-       manifest := strings.Replace(gatewayManifest, "RAPP-NAME", appName, -1)
-       manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
+        config = template.Must(template.ParseFiles("./templates/Gateway-template.txt"))
+        var manifest bytes.Buffer
+        err := config.Execute(&manifest, inputs)
+        if err != nil {
+                return "", err
+        }
 
        gt := &netv1beta1.Gateway{}
-       dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
+       dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest.String())), 1000)
 
        if err := dec.Decode(&gt); err != nil {
                return "", err
@@ -181,13 +110,17 @@ func createGateway(clientset *versioned.Clientset, appName string) (string, erro
        return result.GetName(), nil
 }
 
-func createVirtualService(clientset *versioned.Clientset, appName string) (string, error) {
+func createVirtualService(clientset *versioned.Clientset) (string, error) {
        vsClient := clientset.NetworkingV1beta1().VirtualServices(NAMESPACE)
-       manifest := strings.Replace(virtualServiceManifest, "RAPP-NAME", appName, -1)
-       manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
+        config = template.Must(template.ParseFiles("./templates/VirtualService-template.txt"))
+        var manifest bytes.Buffer
+        err := config.Execute(&manifest, inputs)
+        if err != nil {
+                return "", err
+        }
 
        vs := &netv1beta1.VirtualService{}
-       dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
+       dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest.String())), 1000)
 
        if err := dec.Decode(&vs); err != nil {
                return "", err
@@ -203,14 +136,17 @@ func createVirtualService(clientset *versioned.Clientset, appName string) (strin
        return result.GetName(), nil
 }
 
-func createRequestAuthentication(clientset *versioned.Clientset, appName, realmName string) (string, error) {
+func createRequestAuthentication(clientset *versioned.Clientset) (string, error) {
        raClient := clientset.SecurityV1beta1().RequestAuthentications(NAMESPACE)
-       manifest := strings.Replace(requestAuthenticationManifest, "RAPP-NAME", appName, -1)
-       manifest = strings.Replace(manifest, "REALM-NAME", realmName, -1)
-       manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
+        config = template.Must(template.ParseFiles("./templates/RequestAuthentication-template.txt"))
+        var manifest bytes.Buffer
+        err := config.Execute(&manifest, inputs)
+        if err != nil {
+                return "", err
+        }
 
        ra := &secv1beta1.RequestAuthentication{}
-       dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
+       dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest.String())), 1000)
 
        if err := dec.Decode(&ra); err != nil {
                return "", err
@@ -226,16 +162,17 @@ func createRequestAuthentication(clientset *versioned.Clientset, appName, realmN
        return result.GetName(), nil
 }
 
-func createAuthorizationPolicy(clientset *versioned.Clientset, appName, realmName, roleName, methodName string) (string, error) {
+func createAuthorizationPolicy(clientset *versioned.Clientset) (string, error) {
        apClient := clientset.SecurityV1beta1().AuthorizationPolicies(NAMESPACE)
-       manifest := strings.Replace(authorizationPolicyManifest, "RAPP-NAME", appName, -1)
-       manifest = strings.Replace(manifest, "REALM-NAME", realmName, -1)
-       manifest = strings.Replace(manifest, "ROLE-NAME", roleName, -1)
-       manifest = strings.Replace(manifest, "METHOD-NAME", methodName, -1)
-       manifest = strings.Replace(manifest, "RAPP-NS", NAMESPACE, -1)
+        config = template.Must(template.ParseFiles("./templates/AuthorizationPolicy-template.txt"))
+        var manifest bytes.Buffer
+        err := config.Execute(&manifest, inputs)
+        if err != nil {
+                return "", err
+        }
 
        ap := &secv1beta1.AuthorizationPolicy{}
-       dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000)
+       dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest.String())), 1000)
 
        if err := dec.Decode(&ap); err != nil {
                return "", err
@@ -251,7 +188,33 @@ func createAuthorizationPolicy(clientset *versioned.Clientset, appName, realmNam
        return result.GetName(), nil
 }
 
-func removeGateway(clientset *versioned.Clientset, appName string) {
+func createEnvoyFilter(clientset *versioned.Clientset) (string, error) {
+        efClient := clientset.NetworkingV1alpha3().EnvoyFilters(NAMESPACE)
+       config = template.Must(template.ParseFiles("./templates/EnvoyFilter-template.txt"))
+       var manifest bytes.Buffer
+        err := config.Execute(&manifest, inputs)
+        if err != nil {
+                return "", err
+        }
+
+        ef := &netv1alpha3.EnvoyFilter{}
+        dec := k8Yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest.String())), 1000)
+
+        if err = dec.Decode(&ef); err != nil {
+                return "", err
+        }
+
+        result, err := efClient.Create(context.TODO(), ef, metav1.CreateOptions{})
+
+        if err != nil {
+                return "", err
+        }
+
+        fmt.Printf("Create Envoy Filter %s \n", result.GetName())
+        return result.GetName(), nil
+}
+
+func removeGateway(clientset *versioned.Clientset) {
        gtClient := clientset.NetworkingV1beta1().Gateways(NAMESPACE)
        err := gtClient.Delete(context.TODO(), "nonrtric-istio-"+appName+"-gateway", metav1.DeleteOptions{})
        if err != nil {
@@ -261,7 +224,7 @@ func removeGateway(clientset *versioned.Clientset, appName string) {
        }
 }
 
-func removeVirtualService(clientset *versioned.Clientset, appName string) {
+func removeVirtualService(clientset *versioned.Clientset) {
        vsClient := clientset.NetworkingV1beta1().VirtualServices(NAMESPACE)
        err := vsClient.Delete(context.TODO(), "nonrtric-istio-"+appName+"-vs", metav1.DeleteOptions{})
        if err != nil {
@@ -271,7 +234,7 @@ func removeVirtualService(clientset *versioned.Clientset, appName string) {
        }
 }
 
-func removeRequestAuthentication(clientset *versioned.Clientset, appName string) {
+func removeRequestAuthentication(clientset *versioned.Clientset) {
        raClient := clientset.SecurityV1beta1().RequestAuthentications(NAMESPACE)
        err := raClient.Delete(context.TODO(), "jwt-"+appName, metav1.DeleteOptions{})
        if err != nil {
@@ -281,7 +244,7 @@ func removeRequestAuthentication(clientset *versioned.Clientset, appName string)
        }
 }
 
-func removeAuthorizationPolicy(clientset *versioned.Clientset, appName string) {
+func removeAuthorizationPolicy(clientset *versioned.Clientset) {
        apClient := clientset.SecurityV1beta1().AuthorizationPolicies(NAMESPACE)
        err := apClient.Delete(context.TODO(), appName+"-policy", metav1.DeleteOptions{})
        if err != nil {
@@ -291,30 +254,41 @@ func removeAuthorizationPolicy(clientset *versioned.Clientset, appName string) {
        }
 }
 
+func removeEnvoyFilter(clientset *versioned.Clientset) {
+       efClient := clientset.NetworkingV1alpha3().EnvoyFilters(NAMESPACE)
+        err := efClient.Delete(context.TODO(), appName+"-outbound-filter", metav1.DeleteOptions{})
+        if err != nil {
+                fmt.Println(err)
+        } else {
+                fmt.Println("Deleted EnvoyFilter " + appName + "-outbound-filter")
+        }
+}
+
 func createIstioPolicy(res http.ResponseWriter, req *http.Request) {
        query := req.URL.Query()
        realmName := query.Get("realm")
        appName := query.Get("name")
        roleName := query.Get("role")
        methodName := query.Get("method")
+       inputs = TemplateConfig{Name: appName, Namespace: NAMESPACE, Realm: realmName, Role: roleName, Method: methodName }
        var msg string
        clientset := connectToK8s()
-       _, err := createGateway(clientset, appName)
+       _, err := createGateway(clientset)
        if err != nil {
                msg = err.Error()
                fmt.Println(err.Error())
        } else {
-               _, err := createVirtualService(clientset, appName)
+               _, err := createVirtualService(clientset)
                if err != nil {
                        msg = err.Error()
                        fmt.Println(err.Error())
                } else {
-                       _, err := createRequestAuthentication(clientset, appName, realmName)
+                       _, err := createRequestAuthentication(clientset)
                        if err != nil {
                                msg = err.Error()
                                fmt.Println(err.Error())
                        } else {
-                               _, err := createAuthorizationPolicy(clientset, appName, realmName, roleName, methodName)
+                               _, err := createAuthorizationPolicy(clientset)
                                if err != nil {
                                        msg = err.Error()
                                        fmt.Println(err.Error())
@@ -331,20 +305,51 @@ func createIstioPolicy(res http.ResponseWriter, req *http.Request) {
        res.Write(data)
 }
 
+func createIstioFilter(res http.ResponseWriter, req *http.Request) {
+        query := req.URL.Query()
+        realmName := query.Get("realm")
+        clientId := query.Get("client")
+        appName := query.Get("name")
+        authType := query.Get("authType")
+       inputs = TemplateConfig{Name: appName, Namespace: NAMESPACE, Realm: realmName, Client: clientId, Authenticator: authType}
+        var msg string
+        clientset := connectToK8s()
+        _, err := createEnvoyFilter(clientset)
+        if err != nil {
+                msg = err.Error()
+                fmt.Println(err.Error())
+        }
+        // create response binary data
+        data := []byte(msg) // slice of bytes
+        // write `data` to response
+        res.Write(data)
+}
+
 func removeIstioPolicy(res http.ResponseWriter, req *http.Request) {
        query := req.URL.Query()
-       appName := query.Get("name")
+       appName = query.Get("name")
        clientset := connectToK8s()
-       removeAuthorizationPolicy(clientset, appName)
-       removeRequestAuthentication(clientset, appName)
-       removeVirtualService(clientset, appName)
-       removeGateway(clientset, appName)
+       removeAuthorizationPolicy(clientset)
+       removeRequestAuthentication(clientset)
+       removeVirtualService(clientset)
+       removeGateway(clientset)
+}
+
+func removeIstioFilter(res http.ResponseWriter, req *http.Request) {
+        query := req.URL.Query()
+        appName = query.Get("name")
+        clientset := connectToK8s()
+        removeEnvoyFilter(clientset)
 }
 
 func main() {
-       createIstioHandler := http.HandlerFunc(createIstioPolicy)
-       http.Handle("/create", createIstioHandler)
-       removeIstioHandler := http.HandlerFunc(removeIstioPolicy)
-       http.Handle("/remove", removeIstioHandler)
+       createIstioPolicyHandler := http.HandlerFunc(createIstioPolicy)
+       http.Handle("/create-policy", createIstioPolicyHandler)
+       removeIstioPolicyHandler := http.HandlerFunc(removeIstioPolicy)
+       http.Handle("/remove-policy", removeIstioPolicyHandler)
+       createIstioFilterHandler := http.HandlerFunc(createIstioFilter)
+       http.Handle("/create-filter", createIstioFilterHandler)
+       removeIstioFilterHandler := http.HandlerFunc(removeIstioFilter)
+       http.Handle("/remove-filter", removeIstioFilterHandler)
        http.ListenAndServe(":9000", nil)
 }