Add jwt-proxy functionality 94/9294/5
authorktimoney <kevin.timoney@est.tech>
Mon, 3 Oct 2022 14:02:44 +0000 (15:02 +0100)
committerJohn Keeney <john.keeney@est.tech>
Wed, 26 Oct 2022 11:42:45 +0000 (11:42 +0000)
Issue-ID: NONRTRIC-634
Change-Id: Iedb39691a1dad212f9ad69b127287291496eaaf8
Signed-off-by: ktimoney <kevin.timoney@est.tech>
76 files changed:
service-exposure/Dockerfile_jwt [new file with mode: 0644]
service-exposure/Dockerfile_rhi
service-exposure/Dockerfile_rhwi1 [new file with mode: 0644]
service-exposure/Dockerfile_rhwi2 [new file with mode: 0644]
service-exposure/Dockerfile_rhwp [new file with mode: 0644]
service-exposure/Dockerfile_rim
service-exposure/Dockerfile_rkm
service-exposure/IstioOperator.yaml [new file with mode: 0644]
service-exposure/MutatingWebhookConfiguration.yaml [new file with mode: 0644]
service-exposure/README.md
service-exposure/chartmuseum.yaml
service-exposure/charts/rapp-helloworld-invoker1/.helmignore [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/Chart.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/templates/NOTES.txt [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/templates/_helpers.tpl [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/templates/clusterrole.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/templates/deployment.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/templates/hpa.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/templates/ingress.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/templates/service.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/templates/serviceaccount.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/templates/tests/test-connection.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker1/values.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/.helmignore [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/Chart.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/templates/NOTES.txt [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/templates/_helpers.tpl [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/templates/clusterrole.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/templates/deployment.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/templates/hpa.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/templates/ingress.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/templates/service.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/templates/serviceaccount.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/templates/tests/test-connection.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-invoker2/values.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/.helmignore [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/Chart.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/templates/NOTES.txt [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/templates/_helpers.tpl [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/templates/clusterrole.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/templates/deployment.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/templates/hpa.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/templates/ingress.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/templates/service.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/templates/serviceaccount.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/templates/tests/test-connection.yaml [new file with mode: 0644]
service-exposure/charts/rapp-helloworld-provider/values.yaml [new file with mode: 0644]
service-exposure/deploy_rapp.sh [new file with mode: 0644]
service-exposure/keycloak.sh [new file with mode: 0644]
service-exposure/keycloak.yaml
service-exposure/postgres.yaml
service-exposure/rapps-helm-installer.go
service-exposure/rapps-helm-installer.yaml
service-exposure/rapps-istio-mgr.go
service-exposure/rapps-istio-mgr.yaml
service-exposure/rapps-jwt.go [new file with mode: 0644]
service-exposure/rapps-keycloak-mgr.go
service-exposure/rapps-keycloak-mgr.yaml
service-exposure/rapps-rapp-helloworld-invoker1.go [new file with mode: 0644]
service-exposure/rapps-rapp-helloworld-invoker2.go [new file with mode: 0644]
service-exposure/rapps-rapp-helloworld-provider.go [new file with mode: 0644]
service-exposure/rapps-rapp-invoker.go
service-exposure/rapps-rapp-provider.go
service-exposure/rapps-webhook.go [new file with mode: 0644]
service-exposure/rapps-webhook.yaml [new file with mode: 0644]
service-exposure/rp_test.sh
service-exposure/start_pods.sh
service-exposure/stop_pods.sh
service-exposure/templates/AuthorizationPolicy-template.txt [new file with mode: 0644]
service-exposure/templates/EnvoyFilter-template.txt [new file with mode: 0644]
service-exposure/templates/Gateway-template.txt [new file with mode: 0644]
service-exposure/templates/RequestAuthentication-template.txt [new file with mode: 0644]
service-exposure/templates/VirtualService-template.txt [new file with mode: 0644]
service-exposure/undeploy_rapp.sh [new file with mode: 0644]
service-exposure/utils/generatejwt/generatejwt.go [new file with mode: 0644]
service-exposure/utils/pemtojwks/pemtojwks.go [new file with mode: 0644]

diff --git a/service-exposure/Dockerfile_jwt b/service-exposure/Dockerfile_jwt
new file mode 100644 (file)
index 0000000..104d3a8
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+FROM golang:latest
+RUN mkdir /app
+COPY ./rapps-jwt /app
+RUN chmod +x /app/rapps-jwt
+WORKDIR /app
+ENTRYPOINT ["/app/rapps-jwt"]
index 6332b20..1194c35 100644 (file)
@@ -17,9 +17,9 @@
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=========================================================
 #
-FROM golang:latest 
-RUN mkdir /app 
+FROM golang:latest
+RUN mkdir /app
 COPY ./rapps-helm-installer /app
 RUN chmod +x /app/rapps-helm-installer
-WORKDIR /app 
+WORKDIR /app
 ENTRYPOINT ["/app/rapps-helm-installer"]
diff --git a/service-exposure/Dockerfile_rhwi1 b/service-exposure/Dockerfile_rhwi1
new file mode 100644 (file)
index 0000000..4b5413f
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+FROM golang:latest
+RUN mkdir /app
+COPY ./rapps-rapp-helloworld-invoker1 /app
+RUN chmod +x /app/rapps-rapp-helloworld-invoker1
+WORKDIR /app
+ENTRYPOINT ["/app/rapps-rapp-helloworld-invoker1"]
diff --git a/service-exposure/Dockerfile_rhwi2 b/service-exposure/Dockerfile_rhwi2
new file mode 100644 (file)
index 0000000..dd01243
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+FROM golang:latest
+RUN mkdir /app
+COPY ./rapps-rapp-helloworld-invoker2 /app
+RUN chmod +x /app/rapps-rapp-helloworld-invoker2
+WORKDIR /app
+ENTRYPOINT ["/app/rapps-rapp-helloworld-invoker2"]
diff --git a/service-exposure/Dockerfile_rhwp b/service-exposure/Dockerfile_rhwp
new file mode 100644 (file)
index 0000000..099315a
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+FROM golang:latest
+RUN mkdir /app
+COPY ./rapps-rapp-helloworld-provider /app
+RUN chmod +x /app/rapps-rapp-helloworld-provider
+WORKDIR /app
+ENTRYPOINT ["/app/rapps-rapp-helloworld-provider"]
index f75d7fd..dc4c26b 100644 (file)
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=========================================================
 #
-FROM golang:latest 
-RUN mkdir /app 
+FROM golang:latest
+RUN mkdir /app
 COPY ./rapps-istio-mgr /app
+RUN mkdir /app/templates
+ADD templates /app/templates
 RUN chmod +x /app/rapps-istio-mgr
-WORKDIR /app 
+WORKDIR /app
 ENTRYPOINT ["/app/rapps-istio-mgr"]
index cb4fc65..f1cd6bc 100644 (file)
@@ -17,9 +17,9 @@
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=========================================================
 #
-FROM golang:latest 
-RUN mkdir /app 
+FROM golang:latest
+RUN mkdir /app
 COPY ./rapps-keycloak-mgr /app
 RUN chmod +x /app/rapps-keycloak-mgr
-WORKDIR /app 
+WORKDIR /app
 ENTRYPOINT ["/app/rapps-keycloak-mgr"]
diff --git a/service-exposure/IstioOperator.yaml b/service-exposure/IstioOperator.yaml
new file mode 100644 (file)
index 0000000..c2c1484
--- /dev/null
@@ -0,0 +1,82 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+apiVersion: install.istio.io/v1alpha1
+kind: IstioOperator
+spec:
+  profile: demo
+  meshConfig:
+    extensionProviders:
+    - name: "opa-default-grpc"
+      envoyExtAuthzGrpc:
+        service: "opa.default.svc.cluster.local"
+        port: "9191"
+        includeRequestBodyInCheck:
+          maxRequestBytes: 1000000
+    - name: "opa-default-http"
+      envoyExtAuthzHttp:
+        service: "opa.default.svc.cluster.local"
+        port: "8181"
+        includeRequestHeadersInCheck: ["authorization", "path"]
+        includeRequestBodyInCheck:
+          maxRequestBytes: 1000000
+    - name: "opa-local"
+      envoyExtAuthzGrpc:
+        service: "local-opa-grpc.local"
+        port: "9191"
+    accessLogEncoding: TEXT
+    accessLogFile: "/dev/stdout"
+    accessLogFormat: ""
+    outboundTrafficPolicy:
+      mode: REGISTRY_ONLY
+  values:
+    pilot:
+      jwksResolverExtraRootCA: |
+        -----BEGIN CERTIFICATE-----
+        MIIFdTCCA12gAwIBAgIUb2mMsNxZ3fpdLt0memNEwSs+yCUwDQYJKoZIhvcNAQEL
+        BQAwSjELMAkGA1UEBhMCSUUxDDAKBgNVBAsMA0VTVDERMA8GA1UEAwwIZXN0LnRl
+        Y2gxGjAYBgkqhkiG9w0BCQEWC2NhQG1haWwuY29tMB4XDTIyMDMyOTEyMjMxOVoX
+        DTMyMDMyNjEyMjMxOVowSjELMAkGA1UEBhMCSUUxDDAKBgNVBAsMA0VTVDERMA8G
+        A1UEAwwIZXN0LnRlY2gxGjAYBgkqhkiG9w0BCQEWC2NhQG1haWwuY29tMIICIjAN
+        BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAy2E9PlJyZBh64gxnqrhB7ELS59TK
+        mKRZEgyWYCyS54sOsVLt7HwrzeHxMqhccyEB3+S0jqgVFe7RQ2dEIqc9H1upG2TH
+        Cznz7+epYXFj7wRfQAXM53mEJYIVPcjJ31iFBHKURC6l/ZBLENNG+mXBN9cO7nMe
+        b99w8Sc5jVMy9VmKDZMzJildtWhyEGEDq4C69TAJq8zfvPExkOZW9iSg25FaCoip
+        IO19EYVxl6BYnjgKr48s1XyREBUnOkw6IeVLzD/2co5UpJd40yolXAG8eDxxSGzT
+        EjyVMR3tph86FQ8H053lYB5Y3u6iwCdALf9TvUpEv+ZL4BcB+I4U0RdtLQGL2iuv
+        9NLeqVAfmtXC3st+DgukxvJA3+iGDGyssvY3EF3eCB9QnjjbDwvZ4raG4DIcBNQ3
+        FfpfpoSswXI4KU2JXgS/V28Az46NIFwwT3WvwhFT5aCUcInNPAF2vDSUfDvlHl39
+        BSSKAqsPnvJIDTnlmJoSo28uca2SkSkXL2N43vGOPV4/UYRIz+bqSFNfu48nfe1I
+        E83PKTCTDum+iOscteF1xMU3KrWLpdkBzPW1PfVK6OcAgbKZvfBGNdNOmygfMj5t
+        Slw0bc2Gpd1ISJyQK0L2DVOSMeB6+PyDdJEYUVe+Xh2uqnaGJnAS90//X/FiOJrJ
+        Y5GrgeVLAkDyOjcCAwEAAaNTMFEwHQYDVR0OBBYEFHoCuHWgHsN1cS7TRuJgk1Yv
+        deY7MB8GA1UdIwQYMBaAFHoCuHWgHsN1cS7TRuJgk1YvdeY7MA8GA1UdEwEB/wQF
+        MAMBAf8wDQYJKoZIhvcNAQELBQADggIBALp0D+Sw09OxZhq8CGw/fQn+AScY9JSE
+        E/4C+jVwSVygi7BKcJfqy8aq7cGe+O9sAEnmxDrle1oECVIXX+mhhS7cD5kRdOsb
+        WAjJBqi+B6YgNuawLfQldnHJV/opjb0FBytaGpEMWYsAj0xcoVe4Nj/x7myQ4qoD
+        Y8r8wEFriOwTk+0dICg40I2EUeq5qoJ7Q5bbdYPfe8EhJAkN4u7xJ6P6GDY6Zvoo
+        JpYSSAaKLZb9yd4SxAoDvyuEZL6YNX8vgfPEZqVi2lm5uDkeE+xqWhL2j0ECKXPN
+        PLQMFBCaVPO9RueiwV/P/l0DuChY7dSAHn9kqdS6PlSGe411OGTpxz5laD9Ho4a9
+        UOAurbtu76wAPnsxszAxMAGqEXvZgcX+zUBm4uGPpLUu5vIiWgE/DpwmIpT5jwDu
+        EV0e7C43q3kT5ieqzxDb3gvUWdQZ4Qg6qa8js7KfKH7L0ToCtZACnpdVXjxE1Mp6
+        aCKAPPo8AJm2YdS0Zyj1w8ZN6tDStZ6sfFyEkcRiLOF0pL0qJKw/aqgZd0cHCZed
+        z9p+zpuSbJgnEqax0G7fF5hGofUuCIz4F8CNiehjpZDrCHqPrbCsUveu4iP+cw2N
+        /DZsEJUr0qL+QsAll2L6Zm8z1bAGxomxfFqUAHPep+msFyKT6W2SXz3MzTClq1JK
+        CruKkw029sEv
+        -----END CERTIFICATE-----
diff --git a/service-exposure/MutatingWebhookConfiguration.yaml b/service-exposure/MutatingWebhookConfiguration.yaml
new file mode 100644 (file)
index 0000000..b0947aa
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+  name: jwt-proxy-webhook
+  namespace: default
+webhooks:
+  - name: rapps-webhook.default.svc.cluster.local
+    admissionReviewVersions:
+      - "v1beta1"
+    sideEffects: "None"
+    timeoutSeconds: 30
+    objectSelector:
+      matchLabels:
+        app.kubernetes.io/name: rapp-helloworld-invoker1
+    clientConfig:
+      service:
+        name: jwt-proxy-admission-controller
+        namespace: default
+        path: "/inject-sidecar"
+      caBundle: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURhakNDQWxLZ0F3SUJBZ0lVTlZFcUZwSUJMUEZUOGd2L3hQK245L2ZvTy80d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1RURUxNQWtHQTFVRUJoTUNTVVV4RURBT0JnTlZCQWdUQjFkbFltaHZiMnN4RHpBTkJnTlZCQWNUQmtSMQpZbXhwYmpFTU1Bb0dBMVVFQ2hNRFJWTlVNUTB3Q3dZRFZRUUxFd1JQY21GdU1CNFhEVEl5TURreU1EQTRNRGN3Ck1Gb1hEVEkzTURreE9UQTRNRGN3TUZvd1RURUxNQWtHQTFVRUJoTUNTVVV4RURBT0JnTlZCQWdUQjFkbFltaHYKYjJzeER6QU5CZ05WQkFjVEJrUjFZbXhwYmpFTU1Bb0dBMVVFQ2hNRFJWTlVNUTB3Q3dZRFZRUUxFd1JQY21GdQpNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXArM3lhc2VHUVpOS1VCakVJcFF6CktUZFI5bEVFTDhGeitGRGIrM0YwalQ2cWtoMko5cmJYdUx0V0dWZm5RQWpXb1JpaHlUV3F3RlR6V2lMNHVtK0gKNzVYSm1ucHlqbkRJRStaUGZpcFR0SW40cHhSZ3Z3WXl5a0pjeGI4blN3a21IM2NVRkVLMHJnbEEvLzVMV0RuWgpIQkl2VkhFUzlGYktwVFBEZFlNRFJ2K3dNNGk1ZWVOM1djOCtnZ0hYZW1tc3pkRG9mc0dMTU1iNkpXQlY0MEs0ClhHRDdheEYwelBIT3RHblhlU21zL1lVTlB4R3Z5WWpmZHJqSW1kL2xKUCtDQysvMlhuaEZYYUYzSzJxbE9uQU4KUGVoOGRPNzdNZzVjU01JQkhwbll1RTVqUy95YmZ0RGRSWDcxRm9ZUmJ0MXZsOXNuVC9zNFhxTDB2bHBCRmVyMApSd0lEQVFBQm8wSXdRREFPQmdOVkhROEJBZjhFQkFNQ0FRWXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QWRCZ05WCkhRNEVGZ1FVcDQyM3B4NnUxbTYwZnhCNEJWYmFWR2gxaGwwd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFHaHYKc25jc1g0dUl2S1lZRUdCNitEYmNmdlViS1o2clQ1Ykx3OUV1aFpDSUJiS0xTOFRLMHFqV2dyM0JZWUsyRFA2UgpTcmhzOHRSbkQ2VCtPL1dMdWpPOXM4SUpBbGQvRkQzenJyZWs1YW16RndQb1JiWVZ6OXY4SG1HblRRY2JZWEFYCmlzcjg5Z1QzRFRLbkRxTHEyUTU2WnBiN2dLbFZWNXZKNjVaVFRzYUwxc2oxK1d0bDB0emcrektMNHdrckRqK0wKRzd4blYrNDY3eEUwSnora3JOaFYzaHJEYmhpOUVsRVNRTnVHeURsTUVuY2dvSEFqMmh4WnVINEVUTXJyYWxSWgphQTI3c1ZDNGlMYmJsQWZ0THRWb1YycGpVdTdDVWwrQ1pOZ2tFRGl1d05weWQvZzdlVmYvVk0vakt5TTFiODQ4Ck5nYlZmcjNhelFlOUIyc3kvQnc9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
+    rules:
+      - operations: [ "CREATE" ]
+        apiGroups: [""]
+        apiVersions: ["v1"]
+        resources: ["pods"]
index 00da4d0..c6cdac3 100644 (file)
@@ -1,6 +1,28 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
 This collection of files represent rapp service exposure prototyping in O-RAN.
-Prerequisites: Istio should be installed on your cluster with the demo profile (istioctl install --set profile=demo). Please refer to the istio documentation for more information.
+Prerequisites: Istio should be installed on your cluster with the demo profile.
+  istioctl install --set profile=demo
+Please refer to the istio documentation for more information.
 The deployments have been implemented and tested using minikube.
+If you are not using minikube, references to "minikube ip" should be changed to the appropiate value for you host.
 To replicate these tests you will need to setup the various host path referenced in the yaml files on your own machine.
 
 chartmuseum.yaml:             path: /var/chartmuseum/charts
@@ -12,30 +34,42 @@ rapps-keycloak-mgr.yaml:      path: /var/rapps/certs
 
 or change them to match your own setup.
 
+The certs directory contains 2 shell scripts for creating the server and client certs: server_certs.sh and client_certs.sh
+Certs generated by the server_certs.sh script: rootCA.crt, tls.crt and tls.key go in the "/var/keycloak/certs" directory
+Certs generated by the client_certs.sh script: client.crt, client.key, client_pub.key and rootCA.crt go in the "/var/rapps/certs" directory
+
 Create the istio-nonrtric namespace and enable it for istio injection
 
-   kubectl create ns istio-nonrtric 
+   kubectl create ns istio-nonrtric
 
    kubectl label namespace istio-nonrtric istio-injection=enabled
 
 
 All go programs need to be built prior to running the Dockerfiles
 
-   go build rapps-helm-installer.go    
-   go build rapps-keycloak-mgr.go  
-   go build rapps-istio-mgr.go     
+   go build rapps-helm-installer.go
+   go build rapps-keycloak-mgr.go
+   go build rapps-istio-mgr.go
    go build rapps-rapp-provider.go
    go build rapps-rapp-invoker.go
+   go build rapps-webhook.go
+   go build rapps-jwt.go
+   go build rapps-rapp-helloworld-provider.go
+   go build rapps-rapp-helloworld-invoker1.go
+   go build rapps-rapp-helloworld-invoker2.go
 
 Once the go programs have been compile you then need to build a docker image for each of them.
 
    docker build -f Dockerfile_rim . -t <tag prefix>/rapps-istio-mgr
    docker build -f Dockerfile_rkm . -t <tag prefix>/rapps-keycloak-mgr
    docker build -f Dockerfile_rhi . -t <tag prefix>/rapps-helm-installer
-   docker build -f Dockerfile_rri . -t <tag prefix>/rapps-rapp-invoker
-   docker build -f Dockerfile_rrp . -t <tag prefix>/rapps-rapp-provider
+   docker build -f Dockerfile_wh . -t <tag prefix>/rapps-webhook
+   docker build -f Dockerfile_jwt . -t <tag prefix>/rapps-jwt
+   docker build -f Dockerfile_rhwp  . -t <tag prefix>/rapps-rapp-helloworld-provider
+   docker build -f Dockerfile_rhwi1  . -t <tag prefix>/rapps-rapp-helloworld-invoker1
+   docker build -f Dockerfile_rhwi2  . -t <tag prefix>/rapps-rapp-helloworld-invoker2
 
-Image references in the yaml files/helm charts should be changed to match your own tagged images. 
+Image references in the yaml files/helm charts should be changed to match your own tagged images.
 
 You will need to package your rapp charts and copy them to the /var/chartmuseum/charts directory before starting.
 
@@ -51,20 +85,21 @@ Start keycloak and postgres in the default namespace with istio injection:
 
    istioctl kube-inject -f postgres.yaml | kubectl apply -f -
    istioctl kube-inject -f keycloak.yaml | kubectl apply -f -
+or use the keycloak.sh deploy script
 
-To start the management pods run: 
+To start the management pods run:
 
    start_pods.sh
 
-Run: 
-   kubectl get pods to ensure all managements pods are up and running
-   NAME                                             READY   STATUS    RESTARTS   AGE
-   chartmuseum-deployment-7b8cd4c9d4-tpmhl          1/1     Running   0          8s
-   keycloak-bc6f78f88-zmxlt                         2/2     Running   0          2m20s
-   postgres-6fb4cc8db6-bbhg9                        2/2     Running   0          2m34s
-   rapps-helm-installer-deployment-67476694-sxb2d   1/1     Running   0          6s
-   rapps-istio-mgr-deployment-67c67647b6-scmqc      1/1     Running   0          7s
-   rapps-keycloak-mgr-deployment-7464f87575-trvmx   1/1     Running   0          7s
+Once all pods have been started a list of running pods is displayed at the end of the script:
+NAME                                                         READY   STATUS    RESTARTS   AGE
+chartmuseum-deployment-7b8cd4c9d4-nd7dk                      1/1     Running   0          9s
+jwt-proxy-admission-controller-deployment-66797fb6df-mlk8t   1/1     Running   0          8s
+keycloak-846ff979bc-ndvdf                                    2/2     Running   0          2m16s
+postgres-78b4b9d95-nqjkj                                     2/2     Running   0          2m29s
+rapps-helm-installer-deployment-67476694-n5r24               1/1     Running   0          8s
+rapps-istio-mgr-deployment-67c67647b6-p5s2k                  1/1     Running   0          8s
+rapps-keycloak-mgr-deployment-7464f87575-54h9x               1/1     Running   0          8s
 
 Get the node port for the helm installer that corresponds to port 80
 
@@ -72,13 +107,17 @@ Get the node port for the helm installer that corresponds to port 80
    NAME                   TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
    rapps-helm-installer   NodePort   10.96.58.211   <none>        80:31570/TCP   8m9s
 
-Once these pods are up and running run: 
-   curl http://<minikube ip>:<helm installer node port>/install?chart=<rapp chart name> 
+Once these pods are up and running run:
+   curl http://<minikube ip>:<helm installer node port>/install?chart=<rapp chart name>
    to install your rapp
 
-   e.g. curl http://192.168.49.2:31570/install?chart=rapp-provider
+   e.g. curl http://192.168.49.2:31570/install?chart=rapp-hello-world-provider
         Successfully installed release: rapp-provider
 
+   Alternativley use the deploy_rapp.sh script
+   e.g. ./deploy_rapp.sh rapp-helloworld-provider
+   Note: The line export host= should be changed to the appropaite ip for the host you are running on.
+
 This will setup keycloak realm + client, istio policies and deploy your chart.
 
 You should install both the provider and the invoker to see the pods communicating.
@@ -91,14 +130,19 @@ Check the invoker logs to see the test message:
 If you want to test using the rp_test.sh file, the client_secret field needs be changed to match the secret for you keycloak client.
 You can find this in the keycloak-mgr log.
 
-To uninstall run: 
+To uninstall run:
    curl http://<minikube ip>:<helm installer node port>/uninstall?chart=<rapp chart name>
    e.g. curl http://192.168.49.2:31570/uninstall?chart=rapp-invoker
         Successfully uninstalled release: rapp-invoker
 
-To stop the management pods run: 
+   Alternativley use the undeploy_rapp.sh script
+   e.g. ./undeploy_rapp.sh rapp-helloworld-provider
+
+To stop the management pods and provider/invoker pods at the same time run:
    stop_pods.sh
 
 Remove postgres and keycloak with the following commands:
    kubectl delete -f keycloak.yaml
    kubectl delete -f postgres.yaml
+
+   or use ./keycloak.sh undeploy
index 30aa4e6..987075d 100644 (file)
@@ -23,26 +23,26 @@ metadata:
   name: chartmuseum-deployment
   namespace: default
   labels:
-    app: chartmuseum 
+    app: chartmuseum
 spec:
   selector:
     matchLabels:
-      app: chartmuseum 
+      app: chartmuseum
   template:
     metadata:
       labels:
-        app: chartmuseum 
+        app: chartmuseum
         version: v1
     spec:
       containers:
-      - name: chartmuseum 
-        image: chartmuseum/chartmuseum:latest 
+      - name: chartmuseum
+        image: chartmuseum/chartmuseum:latest
         imagePullPolicy: IfNotPresent
         env:
-        - name: STORAGE 
-          value: local 
-        - name: STORAGE_LOCAL_ROOTDIR 
-          value: /charts 
+        - name: STORAGE
+          value: local
+        - name: STORAGE_LOCAL_ROOTDIR
+          value: /charts
         ports:
         - name: http
           containerPort: 8080
@@ -58,24 +58,24 @@ spec:
           mountPath: /charts
           readOnly: true
       volumes:
-      - name: chartdir 
+      - name: chartdir
         hostPath:
           # Ensure the file directory is created.
-           path: /var/chartmuseum/charts 
+           path: /var/chartmuseum/charts
            type: DirectoryOrCreate
-  replicas: 1 
+  replicas: 1
 ---
 apiVersion: v1
 kind: Service
 metadata:
-  name: chartmuseum 
+  name: chartmuseum
   namespace: default
 spec:
   selector:
-    app: chartmuseum 
+    app: chartmuseum
   ports:
   - name: http
     port: 8080
     targetPort: 8080
-    nodePort: 31580
-  type: LoadBalancer
+    nodePort: 31581
+  type: NodePort
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/.helmignore b/service-exposure/charts/rapp-helloworld-invoker1/.helmignore
new file mode 100644 (file)
index 0000000..0e8a0eb
--- /dev/null
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/Chart.yaml b/service-exposure/charts/rapp-helloworld-invoker1/Chart.yaml
new file mode 100644 (file)
index 0000000..400203d
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+apiVersion: v2
+name: rapp-helloworld-invoker1
+description: A Helm chart for Kubernetes
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "1.16.0"
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/templates/NOTES.txt b/service-exposure/charts/rapp-helloworld-invoker1/templates/NOTES.txt
new file mode 100644 (file)
index 0000000..939a074
--- /dev/null
@@ -0,0 +1,43 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+1. Get the application URL by running these commands:
+{{- if .Values.ingress.enabled }}
+{{- range $host := .Values.ingress.hosts }}
+  {{- range .paths }}
+  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
+  {{- end }}
+{{- end }}
+{{- else if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "rapp-helloworld-invoker1.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "rapp-helloworld-invoker1.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "rapp-helloworld-invoker1.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "rapp-helloworld-invoker1.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/templates/_helpers.tpl b/service-exposure/charts/rapp-helloworld-invoker1/templates/_helpers.tpl
new file mode 100644 (file)
index 0000000..fbac7d3
--- /dev/null
@@ -0,0 +1,62 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "rapp-helloworld-invoker1.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "rapp-helloworld-invoker1.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "rapp-helloworld-invoker1.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "rapp-helloworld-invoker1.labels" -}}
+helm.sh/chart: {{ include "rapp-helloworld-invoker1.chart" . }}
+{{ include "rapp-helloworld-invoker1.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "rapp-helloworld-invoker1.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "rapp-helloworld-invoker1.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "rapp-helloworld-invoker1.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "rapp-helloworld-invoker1.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/templates/clusterrole.yaml b/service-exposure/charts/rapp-helloworld-invoker1/templates/clusterrole.yaml
new file mode 100644 (file)
index 0000000..f713ac9
--- /dev/null
@@ -0,0 +1,41 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app: {{ template "rapp-helloworld-invoker1.name" .}}
+    chart: {{ .Chart.Name }}-{{ .Chart.Version }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+  name: {{ template "rapp-helloworld-invoker1.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+- kind: ServiceAccount
+  name: {{ template "rapp-helloworld-invoker1.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+{{- end -}}
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/templates/deployment.yaml b/service-exposure/charts/rapp-helloworld-invoker1/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..d989b0e
--- /dev/null
@@ -0,0 +1,91 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "rapp-helloworld-invoker1.fullname" . }}
+  labels:
+    {{- include "rapp-helloworld-invoker1.labels" . | nindent 4 }}
+spec:
+  {{- if not .Values.autoscaling.enabled }}
+  replicas: {{ .Values.replicaCount }}
+  {{- end }}
+  selector:
+    matchLabels:
+      {{- include "rapp-helloworld-invoker1.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "rapp-helloworld-invoker1.selectorLabels" . | nindent 8 }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      serviceAccountName: {{ include "rapp-helloworld-invoker1.serviceAccountName" . }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      containers:
+        - name: {{ .Chart.Name }}
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          command: ["/app/rapps-rapp-helloworld-invoker1"]
+          args: [
+                  "-securityEnabled", "{{ .Values.rapp.securityEnabled }}",
+                  "-rapp", "{{ with index .Values.rapp.apps 0 }}{{ .prefix }}{{ end }}",
+                  "-methods", "{{- range .Values.rapp.apps }}{{ join "," .methods }}{{- end }}"
+                ]
+          ports:
+            - name: http
+              containerPort: 9000
+              protocol: TCP
+          livenessProbe:
+            httpGet:
+              path: /health
+              port: 9000
+            initialDelaySeconds: 5
+            periodSeconds: 60
+          readinessProbe:
+            initialDelaySeconds: 5
+            periodSeconds: 10
+            exec:
+              command: ["stat", "init.txt"]
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/templates/hpa.yaml b/service-exposure/charts/rapp-helloworld-invoker1/templates/hpa.yaml
new file mode 100644 (file)
index 0000000..5754224
--- /dev/null
@@ -0,0 +1,49 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+  name: {{ include "rapp-helloworld-invoker1.fullname" . }}
+  labels:
+    {{- include "rapp-helloworld-invoker1.labels" . | nindent 4 }}
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: {{ include "rapp-helloworld-invoker1.fullname" . }}
+  minReplicas: {{ .Values.autoscaling.minReplicas }}
+  maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+  metrics:
+    {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: cpu
+        targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+    {{- end }}
+    {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: memory
+        targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
+    {{- end }}
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/templates/ingress.yaml b/service-exposure/charts/rapp-helloworld-invoker1/templates/ingress.yaml
new file mode 100644 (file)
index 0000000..141e67b
--- /dev/null
@@ -0,0 +1,62 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.ingress.enabled -}}
+{{- $fullName := include "rapp-helloworld-invoker1.fullname" . -}}
+{{- $svcPort := .Values.service.port -}}
+{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1beta1
+{{- else -}}
+apiVersion: extensions/v1beta1
+{{- end }}
+kind: Ingress
+metadata:
+  name: {{ $fullName }}
+  labels:
+    {{- include "rapp-helloworld-invoker1.labels" . | nindent 4 }}
+  {{- with .Values.ingress.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  {{- if .Values.ingress.tls }}
+  tls:
+    {{- range .Values.ingress.tls }}
+    - hosts:
+        {{- range .hosts }}
+        - {{ . | quote }}
+        {{- end }}
+      secretName: {{ .secretName }}
+    {{- end }}
+  {{- end }}
+  rules:
+    {{- range .Values.ingress.hosts }}
+    - host: {{ .host | quote }}
+      http:
+        paths:
+          {{- range .paths }}
+          - path: {{ .path }}
+            backend:
+              serviceName: {{ $fullName }}
+              servicePort: {{ $svcPort }}
+          {{- end }}
+    {{- end }}
+  {{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/templates/service.yaml b/service-exposure/charts/rapp-helloworld-invoker1/templates/service.yaml
new file mode 100644 (file)
index 0000000..d2df6eb
--- /dev/null
@@ -0,0 +1,36 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "rapp-helloworld-invoker1.fullname" . }}
+  labels:
+    {{- include "rapp-helloworld-invoker1.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  ports:
+    - port: {{ .Values.service.port }}
+      targetPort: http
+      protocol: TCP
+      name: http
+  selector:
+    {{- include "rapp-helloworld-invoker1.selectorLabels" . | nindent 4 }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/templates/serviceaccount.yaml b/service-exposure/charts/rapp-helloworld-invoker1/templates/serviceaccount.yaml
new file mode 100644 (file)
index 0000000..40d1cc4
--- /dev/null
@@ -0,0 +1,33 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ include "rapp-helloworld-invoker1.serviceAccountName" . }}
+  labels:
+    {{- include "rapp-helloworld-invoker1.labels" . | nindent 4 }}
+  {{- with .Values.serviceAccount.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/templates/tests/test-connection.yaml b/service-exposure/charts/rapp-helloworld-invoker1/templates/tests/test-connection.yaml
new file mode 100644 (file)
index 0000000..ed38ea7
--- /dev/null
@@ -0,0 +1,36 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+apiVersion: v1
+kind: Pod
+metadata:
+  name: "{{ include "rapp-helloworld-invoker1.fullname" . }}-test-connection"
+  labels:
+    {{- include "rapp-helloworld-invoker1.labels" . | nindent 4 }}
+  annotations:
+    "helm.sh/hook": test
+spec:
+  containers:
+    - name: wget
+      image: busybox
+      command: ['wget']
+      args: ['{{ include "rapp-helloworld-invoker1.fullname" . }}:{{ .Values.service.port }}']
+  restartPolicy: Never
diff --git a/service-exposure/charts/rapp-helloworld-invoker1/values.yaml b/service-exposure/charts/rapp-helloworld-invoker1/values.yaml
new file mode 100644 (file)
index 0000000..8e89cff
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+# Default values for rapp-helloworld-invoker1.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+image:
+  repository: ktimoney/rapps-rapp-helloworld-invoker1
+  pullPolicy: IfNotPresent
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: "latest"
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "rapp-helloworld-invoker1"
+
+rbac:
+  # Specifies whether rbac is enabled
+  create: true
+
+podAnnotations: {}
+
+podSecurityContext: {}
+  # fsGroup: 2000
+
+securityContext: {}
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+ingress:
+  enabled: false
+  annotations: {}
+    # kubernetes.io/ingress.class: nginx
+    # kubernetes.io/tls-acme: "true"
+  hosts:
+    - host: rapp-helloworld-invoker1
+      paths:
+      - path: /
+        backend:
+          serviceName: rapp-helloworld-invoker1
+          servicePort: 80
+  tls: []
+  #  - secretName: chart-example-tls
+  #    hosts:
+  #      - chart-example.local
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+autoscaling:
+  enabled: false
+  minReplicas: 1
+  maxReplicas: 100
+  targetCPUUtilizationPercentage: 80
+  # targetMemoryUtilizationPercentage: 80
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
+
+
+rapp:
+  securityEnabled: true
+  type: invoker
+  realm: demo
+  client: demoprovider-cli
+  authenticator: client-jwt
+  roles:
+  - role : provider-viewer
+    grants:
+      - GET
+  apps:
+  - prefix: rapp-helloworld-provider
+    methods:
+      - GET
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/.helmignore b/service-exposure/charts/rapp-helloworld-invoker2/.helmignore
new file mode 100644 (file)
index 0000000..0e8a0eb
--- /dev/null
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/Chart.yaml b/service-exposure/charts/rapp-helloworld-invoker2/Chart.yaml
new file mode 100644 (file)
index 0000000..3a7db7a
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+apiVersion: v2
+name: rapp-helloworld-invoker2
+description: A Helm chart for Kubernetes
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "1.16.0"
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/templates/NOTES.txt b/service-exposure/charts/rapp-helloworld-invoker2/templates/NOTES.txt
new file mode 100644 (file)
index 0000000..9e38caa
--- /dev/null
@@ -0,0 +1,43 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+1. Get the application URL by running these commands:
+{{- if .Values.ingress.enabled }}
+{{- range $host := .Values.ingress.hosts }}
+  {{- range .paths }}
+  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
+  {{- end }}
+{{- end }}
+{{- else if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "rapp-helloworld-invoker2.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "rapp-helloworld-invoker2.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "rapp-helloworld-invoker2.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "rapp-helloworld-invoker2.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/templates/_helpers.tpl b/service-exposure/charts/rapp-helloworld-invoker2/templates/_helpers.tpl
new file mode 100644 (file)
index 0000000..0999f45
--- /dev/null
@@ -0,0 +1,62 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "rapp-helloworld-invoker2.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "rapp-helloworld-invoker2.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "rapp-helloworld-invoker2.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "rapp-helloworld-invoker2.labels" -}}
+helm.sh/chart: {{ include "rapp-helloworld-invoker2.chart" . }}
+{{ include "rapp-helloworld-invoker2.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "rapp-helloworld-invoker2.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "rapp-helloworld-invoker2.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "rapp-helloworld-invoker2.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "rapp-helloworld-invoker2.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/templates/clusterrole.yaml b/service-exposure/charts/rapp-helloworld-invoker2/templates/clusterrole.yaml
new file mode 100644 (file)
index 0000000..55cb399
--- /dev/null
@@ -0,0 +1,41 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app: {{ template "rapp-helloworld-invoker2.name" .}}
+    chart: {{ .Chart.Name }}-{{ .Chart.Version }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+  name: {{ template "rapp-helloworld-invoker2.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+- kind: ServiceAccount
+  name: {{ template "rapp-helloworld-invoker2.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+{{- end -}}
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/templates/deployment.yaml b/service-exposure/charts/rapp-helloworld-invoker2/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..3333721
--- /dev/null
@@ -0,0 +1,91 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "rapp-helloworld-invoker2.fullname" . }}
+  labels:
+    {{- include "rapp-helloworld-invoker2.labels" . | nindent 4 }}
+spec:
+  {{- if not .Values.autoscaling.enabled }}
+  replicas: {{ .Values.replicaCount }}
+  {{- end }}
+  selector:
+    matchLabels:
+      {{- include "rapp-helloworld-invoker2.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "rapp-helloworld-invoker2.selectorLabels" . | nindent 8 }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      serviceAccountName: {{ include "rapp-helloworld-invoker2.serviceAccountName" . }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      containers:
+        - name: {{ .Chart.Name }}
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          command: ["/app/rapps-rapp-helloworld-invoker2"]
+          args: [
+                  "-securityEnabled", "{{ .Values.rapp.securityEnabled }}",
+                  "-rapp", "{{ with index .Values.rapp.apps 0 }}{{ .prefix }}{{ end }}",
+                  "-methods", "{{- range .Values.rapp.apps }}{{ join "," .methods }}{{- end }}"
+                ]
+          ports:
+            - name: http
+              containerPort: 9000
+              protocol: TCP
+          livenessProbe:
+            httpGet:
+              path: /health
+              port: 9000
+            initialDelaySeconds: 5
+            periodSeconds: 60
+          readinessProbe:
+            initialDelaySeconds: 5
+            periodSeconds: 10
+            exec:
+              command: ["stat", "init.txt"]
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/templates/hpa.yaml b/service-exposure/charts/rapp-helloworld-invoker2/templates/hpa.yaml
new file mode 100644 (file)
index 0000000..2fcc1a8
--- /dev/null
@@ -0,0 +1,49 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+  name: {{ include "rapp-helloworld-invoker2.fullname" . }}
+  labels:
+    {{- include "rapp-helloworld-invoker2.labels" . | nindent 4 }}
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: {{ include "rapp-helloworld-invoker2.fullname" . }}
+  minReplicas: {{ .Values.autoscaling.minReplicas }}
+  maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+  metrics:
+    {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: cpu
+        targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+    {{- end }}
+    {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: memory
+        targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
+    {{- end }}
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/templates/ingress.yaml b/service-exposure/charts/rapp-helloworld-invoker2/templates/ingress.yaml
new file mode 100644 (file)
index 0000000..cfd3538
--- /dev/null
@@ -0,0 +1,62 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.ingress.enabled -}}
+{{- $fullName := include "rapp-helloworld-invoker2.fullname" . -}}
+{{- $svcPort := .Values.service.port -}}
+{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1beta1
+{{- else -}}
+apiVersion: extensions/v1beta1
+{{- end }}
+kind: Ingress
+metadata:
+  name: {{ $fullName }}
+  labels:
+    {{- include "rapp-helloworld-invoker2.labels" . | nindent 4 }}
+  {{- with .Values.ingress.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  {{- if .Values.ingress.tls }}
+  tls:
+    {{- range .Values.ingress.tls }}
+    - hosts:
+        {{- range .hosts }}
+        - {{ . | quote }}
+        {{- end }}
+      secretName: {{ .secretName }}
+    {{- end }}
+  {{- end }}
+  rules:
+    {{- range .Values.ingress.hosts }}
+    - host: {{ .host | quote }}
+      http:
+        paths:
+          {{- range .paths }}
+          - path: {{ .path }}
+            backend:
+              serviceName: {{ $fullName }}
+              servicePort: {{ $svcPort }}
+          {{- end }}
+    {{- end }}
+  {{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/templates/service.yaml b/service-exposure/charts/rapp-helloworld-invoker2/templates/service.yaml
new file mode 100644 (file)
index 0000000..cadc200
--- /dev/null
@@ -0,0 +1,36 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "rapp-helloworld-invoker2.fullname" . }}
+  labels:
+    {{- include "rapp-helloworld-invoker2.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  ports:
+    - port: {{ .Values.service.port }}
+      targetPort: http
+      protocol: TCP
+      name: http
+  selector:
+    {{- include "rapp-helloworld-invoker2.selectorLabels" . | nindent 4 }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/templates/serviceaccount.yaml b/service-exposure/charts/rapp-helloworld-invoker2/templates/serviceaccount.yaml
new file mode 100644 (file)
index 0000000..a92848e
--- /dev/null
@@ -0,0 +1,33 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ include "rapp-helloworld-invoker2.serviceAccountName" . }}
+  labels:
+    {{- include "rapp-helloworld-invoker2.labels" . | nindent 4 }}
+  {{- with .Values.serviceAccount.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/templates/tests/test-connection.yaml b/service-exposure/charts/rapp-helloworld-invoker2/templates/tests/test-connection.yaml
new file mode 100644 (file)
index 0000000..1f2e296
--- /dev/null
@@ -0,0 +1,36 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+apiVersion: v1
+kind: Pod
+metadata:
+  name: "{{ include "rapp-helloworld-invoker2.fullname" . }}-test-connection"
+  labels:
+    {{- include "rapp-helloworld-invoker2.labels" . | nindent 4 }}
+  annotations:
+    "helm.sh/hook": test
+spec:
+  containers:
+    - name: wget
+      image: busybox
+      command: ['wget']
+      args: ['{{ include "rapp-helloworld-invoker2.fullname" . }}:{{ .Values.service.port }}']
+  restartPolicy: Never
diff --git a/service-exposure/charts/rapp-helloworld-invoker2/values.yaml b/service-exposure/charts/rapp-helloworld-invoker2/values.yaml
new file mode 100644 (file)
index 0000000..bd6f5ab
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+# Default values for rapp-helloworld-invoker2.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+image:
+  repository: ktimoney/rapps-rapp-helloworld-invoker2
+  pullPolicy: IfNotPresent
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: "latest"
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "rapp-helloworld-invoker2"
+
+rbac:
+  # Specifies whether rbac is enabled
+  create: true
+
+podAnnotations: {}
+
+podSecurityContext: {}
+  # fsGroup: 2000
+
+securityContext: {}
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+ingress:
+  enabled: false
+  annotations: {}
+    # kubernetes.io/ingress.class: nginx
+    # kubernetes.io/tls-acme: "true"
+  hosts:
+    - host: rapp-helloworld-invoker2
+      paths:
+      - path: /
+        backend:
+          serviceName: rapp-helloworld-invoker2
+          servicePort: 80
+  tls: []
+  #  - secretName: chart-example-tls
+  #    hosts:
+  #      - chart-example.local
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+autoscaling:
+  enabled: false
+  minReplicas: 1
+  maxReplicas: 100
+  targetCPUUtilizationPercentage: 80
+  # targetMemoryUtilizationPercentage: 80
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
+
+
+rapp:
+  securityEnabled: true
+  type: invoker
+  realm: demo
+  client: demoprovider-cli
+  authenticator: client-jwt
+  roles:
+  - role : provider-viewer
+    grants:
+      - GET
+  apps:
+  - prefix: rapp-helloworld-provider
+    methods:
+      - GET
diff --git a/service-exposure/charts/rapp-helloworld-provider/.helmignore b/service-exposure/charts/rapp-helloworld-provider/.helmignore
new file mode 100644 (file)
index 0000000..0e8a0eb
--- /dev/null
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/service-exposure/charts/rapp-helloworld-provider/Chart.yaml b/service-exposure/charts/rapp-helloworld-provider/Chart.yaml
new file mode 100644 (file)
index 0000000..2978a4c
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+apiVersion: v2
+name: rapp-helloworld-provider
+description: A Helm chart for Kubernetes
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "1.16.0"
diff --git a/service-exposure/charts/rapp-helloworld-provider/templates/NOTES.txt b/service-exposure/charts/rapp-helloworld-provider/templates/NOTES.txt
new file mode 100644 (file)
index 0000000..a4ad913
--- /dev/null
@@ -0,0 +1,43 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+1. Get the application URL by running these commands:
+{{- if .Values.ingress.enabled }}
+{{- range $host := .Values.ingress.hosts }}
+  {{- range .paths }}
+  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
+  {{- end }}
+{{- end }}
+{{- else if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "rapp-helloworld-provider.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "rapp-helloworld-provider.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "rapp-helloworld-provider.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "rapp-helloworld-provider.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-provider/templates/_helpers.tpl b/service-exposure/charts/rapp-helloworld-provider/templates/_helpers.tpl
new file mode 100644 (file)
index 0000000..08fd72b
--- /dev/null
@@ -0,0 +1,62 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "rapp-helloworld-provider.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "rapp-helloworld-provider.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "rapp-helloworld-provider.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "rapp-helloworld-provider.labels" -}}
+helm.sh/chart: {{ include "rapp-helloworld-provider.chart" . }}
+{{ include "rapp-helloworld-provider.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "rapp-helloworld-provider.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "rapp-helloworld-provider.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "rapp-helloworld-provider.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "rapp-helloworld-provider.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-provider/templates/clusterrole.yaml b/service-exposure/charts/rapp-helloworld-provider/templates/clusterrole.yaml
new file mode 100644 (file)
index 0000000..7e78328
--- /dev/null
@@ -0,0 +1,41 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app: {{ template "rapp-helloworld-provider.name" .}}
+    chart: {{ .Chart.Name }}-{{ .Chart.Version }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+  name: {{ template "rapp-helloworld-provider.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+- kind: ServiceAccount
+  name: {{ template "rapp-helloworld-provider.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+{{- end -}}
diff --git a/service-exposure/charts/rapp-helloworld-provider/templates/deployment.yaml b/service-exposure/charts/rapp-helloworld-provider/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..6ca7348
--- /dev/null
@@ -0,0 +1,82 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "rapp-helloworld-provider.fullname" . }}
+  labels:
+    {{- include "rapp-helloworld-provider.labels" . | nindent 4 }}
+spec:
+  {{- if not .Values.autoscaling.enabled }}
+  replicas: {{ .Values.replicaCount }}
+  {{- end }}
+  selector:
+    matchLabels:
+      {{- include "rapp-helloworld-provider.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "rapp-helloworld-provider.selectorLabels" . | nindent 8 }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      serviceAccountName: {{ include "rapp-helloworld-provider.serviceAccountName" . }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      containers:
+        - name: {{ .Chart.Name }}
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          ports:
+            - name: http
+              containerPort: 9000
+              protocol: TCP
+          livenessProbe:
+            httpGet:
+              path: /
+              port: http
+          readinessProbe:
+            httpGet:
+              path: /
+              port: http
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-provider/templates/hpa.yaml b/service-exposure/charts/rapp-helloworld-provider/templates/hpa.yaml
new file mode 100644 (file)
index 0000000..3a69608
--- /dev/null
@@ -0,0 +1,49 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+  name: {{ include "rapp-helloworld-provider.fullname" . }}
+  labels:
+    {{- include "rapp-helloworld-provider.labels" . | nindent 4 }}
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: {{ include "rapp-helloworld-provider.fullname" . }}
+  minReplicas: {{ .Values.autoscaling.minReplicas }}
+  maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+  metrics:
+    {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: cpu
+        targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+    {{- end }}
+    {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: memory
+        targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
+    {{- end }}
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-provider/templates/ingress.yaml b/service-exposure/charts/rapp-helloworld-provider/templates/ingress.yaml
new file mode 100644 (file)
index 0000000..80992c2
--- /dev/null
@@ -0,0 +1,62 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.ingress.enabled -}}
+{{- $fullName := include "rapp-helloworld-provider.fullname" . -}}
+{{- $svcPort := .Values.service.port -}}
+{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1beta1
+{{- else -}}
+apiVersion: extensions/v1beta1
+{{- end }}
+kind: Ingress
+metadata:
+  name: {{ $fullName }}
+  labels:
+    {{- include "rapp-helloworld-provider.labels" . | nindent 4 }}
+  {{- with .Values.ingress.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  {{- if .Values.ingress.tls }}
+  tls:
+    {{- range .Values.ingress.tls }}
+    - hosts:
+        {{- range .hosts }}
+        - {{ . | quote }}
+        {{- end }}
+      secretName: {{ .secretName }}
+    {{- end }}
+  {{- end }}
+  rules:
+    {{- range .Values.ingress.hosts }}
+    - host: {{ .host | quote }}
+      http:
+        paths:
+          {{- range .paths }}
+          - path: {{ .path }}
+            backend:
+              serviceName: {{ $fullName }}
+              servicePort: {{ $svcPort }}
+          {{- end }}
+    {{- end }}
+  {{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-provider/templates/service.yaml b/service-exposure/charts/rapp-helloworld-provider/templates/service.yaml
new file mode 100644 (file)
index 0000000..1adda51
--- /dev/null
@@ -0,0 +1,36 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "rapp-helloworld-provider.fullname" . }}
+  labels:
+    {{- include "rapp-helloworld-provider.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  ports:
+    - port: {{ .Values.service.port }}
+      targetPort: http
+      protocol: TCP
+      name: http
+  selector:
+    {{- include "rapp-helloworld-provider.selectorLabels" . | nindent 4 }}
diff --git a/service-exposure/charts/rapp-helloworld-provider/templates/serviceaccount.yaml b/service-exposure/charts/rapp-helloworld-provider/templates/serviceaccount.yaml
new file mode 100644 (file)
index 0000000..23ca505
--- /dev/null
@@ -0,0 +1,33 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ include "rapp-helloworld-provider.serviceAccountName" . }}
+  labels:
+    {{- include "rapp-helloworld-provider.labels" . | nindent 4 }}
+  {{- with .Values.serviceAccount.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+{{- end }}
diff --git a/service-exposure/charts/rapp-helloworld-provider/templates/tests/test-connection.yaml b/service-exposure/charts/rapp-helloworld-provider/templates/tests/test-connection.yaml
new file mode 100644 (file)
index 0000000..7d295f6
--- /dev/null
@@ -0,0 +1,36 @@
+{{/*
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+*/}}
+apiVersion: v1
+kind: Pod
+metadata:
+  name: "{{ include "rapp-helloworld-provider.fullname" . }}-test-connection"
+  labels:
+    {{- include "rapp-helloworld-provider.labels" . | nindent 4 }}
+  annotations:
+    "helm.sh/hook": test
+spec:
+  containers:
+    - name: wget
+      image: busybox
+      command: ['wget']
+      args: ['{{ include "rapp-helloworld-provider.fullname" . }}:{{ .Values.service.port }}']
+  restartPolicy: Never
diff --git a/service-exposure/charts/rapp-helloworld-provider/values.yaml b/service-exposure/charts/rapp-helloworld-provider/values.yaml
new file mode 100644 (file)
index 0000000..bb6ef19
--- /dev/null
@@ -0,0 +1,125 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+# Default values for rapp-helloworld-provider.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+image:
+  repository: ktimoney/rapps-rapp-helloworld-provider
+  pullPolicy: IfNotPresent
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: "latest"
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "rapp-helloworld-provider"
+
+rbac:
+  # Specifies whether rbac should be enabled
+  create: true
+
+podAnnotations: {}
+
+podSecurityContext: {}
+  # fsGroup: 2000
+
+securityContext: {}
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+ingress:
+  enabled: false
+  annotations: {}
+    # kubernetes.io/ingress.class: nginx
+    # kubernetes.io/tls-acme: "true"
+  hosts:
+    - host: rapp-helloworld-provider
+      paths:
+      - path: /
+        backend:
+          serviceName: rapp-helloworld-provider
+          servicePort: 80
+  tls: []
+  #  - secretName: chart-example-tls
+  #    hosts:
+  #      - chart-example.local
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+autoscaling:
+  enabled: false
+  minReplicas: 1
+  maxReplicas: 100
+  targetCPUUtilizationPercentage: 80
+  # targetMemoryUtilizationPercentage: 80
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
+
+rapp:
+  securityEnabled: true
+  type: provider
+  realm: demo
+  client: demoprovider-cli
+  authenticator: client-jwt
+  roles:
+  - role : provider-viewer
+    grants:
+      - GET
+  - role : provider-admin
+    grants:
+      - GET
+      - POST
+      - PUT
+      - DELETE
+
diff --git a/service-exposure/deploy_rapp.sh b/service-exposure/deploy_rapp.sh
new file mode 100644 (file)
index 0000000..4d77350
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+export host=$(minikube ip)
+
+if [ -z "$1" ]
+  then
+    echo "No argument supplied"
+    exit 1
+fi
+
+rapp=$1
+
+echo "Deploying application..."
+echo "------------------------"
+curl http://$host:31570/install?chart=$rapp
+
+echo "\n"
+echo "Waiting for pod to start..."
+echo "---------------------------"
+kubectl wait deployment -n istio-nonrtric $rapp --for=condition=available --timeout=90s
+
+echo ""
+echo "Checking pod status..."
+echo "----------------------"
+kubectl get pods -n istio-nonrtric
+#kubectl get pods --show-labels -n istio-nonrtric
+
+#if [ "$rapp" == "rapp-helloworld-invoker1" ] || [ "$rapp" == "rapp-helloworld-invoker2" ]; then
+if [ "$rapp" != "rapp-helloworld-provider" ]; then
+   echo ""
+   echo "Inspect the log for $rapp..."
+   echo "-----------------------------------------------"
+   kubectl logs -l app.kubernetes.io/name=$rapp -n istio-nonrtric
+fi
+if [ "$rapp" = "rapp-helloworld-invoker1" ]; then
+   echo ""
+   echo "Inspect the log for $rapp jwt sidecar..."
+   echo "-----------------------------------------------------------"
+   kubectl logs -l app.kubernetes.io/name=$rapp -c jwt-proxy -n istio-nonrtric
+fi
diff --git a/service-exposure/keycloak.sh b/service-exposure/keycloak.sh
new file mode 100644 (file)
index 0000000..8338b43
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/bash
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+if [ -z "$1" ]
+  then
+    echo "No argument supplied"
+    exit 1
+fi
+
+OPERATION=$1
+
+if [ "$OPERATION" == "deploy" ]; then
+        echo "Deploying applications..."
+        echo "-------------------------"
+        istioctl kube-inject -f postgres.yaml | kubectl apply -f -
+       sleep 10
+        istioctl kube-inject -f keycloak.yaml | kubectl apply -f -
+        echo ""
+        echo "Waiting for pods to start..."
+        echo "----------------------------"
+        kubectl wait deployment -n default postgres --for=condition=available --timeout=90s
+        kubectl wait deployment -n default keycloak --for=condition=available --timeout=300s
+        echo ""
+        echo "Checking pod status..."
+        echo "----------------------"
+        kubectl get pods -n default
+elif [ "$OPERATION" == "undeploy" ]; then
+        echo "Undeploying applications..."
+        echo "---------------------------"
+       kubectl delete -f keycloak.yaml
+       kubectl delete -f postgres.yaml
+else
+       echo "Unrecogized operation ${OPERATION}"
+       exit 1
+fi
+
+exit 0
index d611c6d..c8c4a63 100644 (file)
@@ -20,7 +20,7 @@
 apiVersion: v1
 kind: ServiceAccount
 metadata:
-  name: keycloak 
+  name: keycloak
   namespace: default
 ---
 apiVersion: v1
@@ -31,12 +31,12 @@ metadata:
     app: keycloak
 spec:
   type: ExternalName
-  externalName: keycloak.local 
+  externalName: keycloak.local
   ports:
   - name: http
     port: 8080
     targetPort: 8080
-    nodePort: 31560 
+    nodePort: 31560
   - name: https
     port: 8443
     targetPort: 8443
@@ -65,20 +65,20 @@ spec:
       initContainers:
       - name: init-postgres
         image: busybox
-        imagePullPolicy: IfNotPresent 
+        imagePullPolicy: IfNotPresent
         command: ['sh', '-c', 'until nc -vz postgres 5432; do echo waiting for postgres db; sleep 2; done;']
-      serviceAccountName: keycloak 
+      serviceAccountName: keycloak
       containers:
       - name: keycloak
-        image: quay.io/keycloak/keycloak:latest
-        imagePullPolicy: IfNotPresent 
+        image: quay.io/keycloak/keycloak:16.1.1
+        imagePullPolicy: IfNotPresent
         env:
         - name: KEYCLOAK_USER
           value: "admin"
         - name: KEYCLOAK_PASSWORD
           value: "admin"
         - name: KEYCLOAK_HTTPS_PORT
-          value: "8443" 
+          value: "8443"
         - name: PROXY_ADDRESS_FORWARDING
           value: "true"
         - name: MANAGEMENT_USER
@@ -89,18 +89,18 @@ spec:
           value: "false"
         - name: DB_VENDOR
           value: "postgres"
-        - name: DB_ADDR 
+        - name: DB_ADDR
           value: "postgres"
-        - name: DB_PORT 
+        - name: DB_PORT
           value: "5432"
         - name: DB_DATABASE
           value: "keycloak"
         - name: DB_USER
-          value: "keycloak" 
+          value: "keycloak"
         - name : DB_PASSWORD
-          value: "keycloak" 
-        - name : X509_CA_BUNDLE 
-          value: /etc/x509/https/rootCA.crt 
+          value: "keycloak"
+        - name : X509_CA_BUNDLE
+          value: /etc/x509/https/rootCA.crt
         ports:
         - name: http
           containerPort: 8080
@@ -111,12 +111,12 @@ spec:
             path: /auth/realms/master
             port: 8080
         volumeMounts:
-        - name: keycloak-certs 
-          mountPath: /etc/x509/https 
+        - name: keycloak-certs
+          mountPath: /etc/x509/https
       volumes:
-      - name: keycloak-certs 
+      - name: keycloak-certs
         hostPath:
-           path: /var/keycloak/certs 
+           path: /var/keycloak/certs
            type: Directory
 ---
 apiVersion: networking.istio.io/v1alpha3
@@ -134,7 +134,7 @@ spec:
     tls:
       mode: PASSTHROUGH
     hosts:
-    - keycloak.est.tech
+    - keycloak.oran.org
   - port:
       number: 80
       name: http
@@ -148,14 +148,14 @@ metadata:
   name: keycloak-tls-vs
 spec:
   hosts:
-  - keycloak.est.tech
+  - keycloak.oran.org
   gateways:
   - kcgateway
   tls:
   - match:
     - port: 443
       sniHosts:
-      - keycloak.est.tech
+      - keycloak.oran.org
     route:
     - destination:
         host: keycloak.default.svc.cluster.local
@@ -170,7 +170,7 @@ spec:
   hosts:
   - "*"
   gateways:
-  - kcgateway 
+  - kcgateway
   http:
   - name: "keycloak-routes"
     match:
index 588dd8e..d0e71c5 100644 (file)
@@ -60,7 +60,7 @@ data:
     DO $$
     BEGIN
       IF NOT EXISTS (SELECT FROM pg_user WHERE  usename = 'capif') THEN
-         CREATE USER capif WITH PASSWORD 'capif'; 
+         CREATE USER capif WITH PASSWORD 'capif';
          GRANT ALL PRIVILEGES ON DATABASE capif TO capif;
       END IF;
     END
@@ -77,11 +77,11 @@ spec:
     app: postgres
   ports:
     - protocol: TCP
-      port: 5432 
+      port: 5432
       nodePort: 30032
-      targetPort: 5432 
+      targetPort: 5432
 ---
-apiVersion: apps/v1 
+apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: postgres
@@ -101,17 +101,17 @@ spec:
       containers:
       - image: nexus3.onap.org:10001/postgres
         name: postgres
-        imagePullPolicy: IfNotPresent 
+        imagePullPolicy: IfNotPresent
         env:
         - name: POSTGRES_DB
-          value: keycloak 
+          value: keycloak
         - name: POSTGRES_USER
-          value: keycloak 
+          value: keycloak
         - name: POSTGRES_PASSWORD
-          value: keycloak 
+          value: keycloak
         - name: PGDATA
-          value: /var/lib/pgsql/data 
-        lifecycle:  
+          value: /var/lib/pgsql/data
+        lifecycle:
           postStart:
             exec:
               command: [ "/bin/sh", "-c", "sleep 10 && psql -U $POSTGRES_USER -f /init.sql" ]
@@ -130,16 +130,16 @@ spec:
           initialDelaySeconds: 15
           timeoutSeconds: 2
         ports:
-        - containerPort: 5432 
+        - containerPort: 5432
           name: postgres
         volumeMounts:
         - name: postgres-persistent-storage
-          mountPath: /var/lib/pgsql/data 
-        - name : tmp-dir  
+          mountPath: /var/lib/pgsql/data
+        - name : tmp-dir
           mountPath: /tmp
         - name: db-init
-          mountPath: /init.sql 
-          subPath: init.sql 
+          mountPath: /init.sql
+          subPath: init.sql
       volumes:
       - name: postgres-persistent-storage
         persistentVolumeClaim:
@@ -147,7 +147,7 @@ spec:
       - name: tmp-dir
         hostPath:
           path: /tmp
-          type: Directory 
+          type: Directory
       - name: db-init
         configMap:
           name: db-init
index dc92fc7..0dc9341 100644 (file)
@@ -17,7 +17,6 @@
 //   limitations under the License.
 //   ========================LICENSE_END===================================
 //
-
 package main
 
 import (
@@ -70,6 +69,7 @@ type Rapp struct {
        SecurityEnabled bool
        Realm           string
        Client          string
+       Authenticator   string
        Roles           []struct {
                Role   string
                Grants []string
@@ -113,30 +113,10 @@ func runInstall(res http.ResponseWriter, req *http.Request) {
                        if err != nil {
                                msg = err.Error()
                        } else {
-                               if rapp.SecurityEnabled && rapp.Type == "provider" {
-                                       // keycloak client setup
-                                       fmt.Println("Setting up keycloak")
-                                       _, err = http.Get("http://rapps-keycloak-mgr.default/create?realm=" + rapp.Realm + "&name=" + rapp.Client + "&role=" + rapp.Roles[0].Role)
-                                       if err != nil {
-                                               msg = err.Error()
-                                       } else {
-                                               fmt.Println("Setting up istio")
-                                               _, err := http.Get("http://rapps-istio-mgr.default/create?name=" + chartName + "&realm=" + rapp.Realm + "&role=" + rapp.Roles[0].Role + "&method=" + rapp.Roles[0].Grants[0])
-                                               if err != nil {
-                                                       msg = err.Error()
-                                               } else {
-                                                       // Install chart
-                                                       fmt.Printf("Installing chart %s to %s namespace\n", chartName, namespace)
-                                                       chart, err = installHelmChart(install)
-                                                       if err != nil {
-                                                               msg = "Error occurred during installation " + err.Error()
-                                                       } else {
-                                                               msg = "Successfully installed release: " + chart
-                                                       }
-                                               }
-                                       }
+                               err := installSecurity(rapp)
+                               if err != nil {
+                                       msg = err.Error()
                                } else {
-                                       // Install chart
                                        fmt.Printf("Installing chart %s to %s namespace\n", chartName, namespace)
                                        chart, err = installHelmChart(install)
                                        if err != nil {
@@ -144,8 +124,8 @@ func runInstall(res http.ResponseWriter, req *http.Request) {
                                        } else {
                                                msg = "Successfully installed release: " + chart
                                        }
-                               }
 
+                               }
                        }
                }
                registrerRapp(chartName, rapp.Type)
@@ -159,6 +139,54 @@ func runInstall(res http.ResponseWriter, req *http.Request) {
        res.Write(data)
 }
 
+func installSecurity(rapp Rapp) error {
+       var url string
+       var params string
+       role := rapp.Roles[0].Role
+       grants := rapp.Roles[0].Grants[0]
+       realm := rapp.Realm
+       client := rapp.Client
+       authenticator := rapp.Authenticator
+
+       if !rapp.SecurityEnabled {
+               return nil
+       }
+       // Different security requirements depending on the rapp type
+       if rapp.Type == "provider" {
+               // keycloak client setup
+               fmt.Println("Setting up keycloak")
+               url = "http://rapps-keycloak-mgr.default/create?"
+               params = "realm=" + realm + "&name=" + client + "&role=" + role + "&authType=" + authenticator
+               url += params
+               _, err := http.Get(url)
+               if err != nil {
+                       return err
+               } else {
+                       fmt.Println("Setting up istio")
+                       url = "http://rapps-istio-mgr.default/create-policy?"
+                       params = "name=" + chartName + "&realm=" + realm + "&role=" + role + "&method=" + grants
+                       url += params
+
+                       _, err := http.Get(url)
+                       if err != nil {
+                               return err
+                       }
+               }
+       } else {
+               fmt.Println("Setting up istio")
+               url = "http://rapps-istio-mgr.default/create-filter?"
+               params = "name=" + chartName + "&realm=" + realm + "&client=" + client + "&authType=" + authenticator
+               url += params
+               _, err := http.Get(url)
+               if err != nil {
+                       return err
+               }
+       }
+
+       return nil
+
+}
+
 func runUninstall(res http.ResponseWriter, req *http.Request) {
        query := req.URL.Query()
        chartName = query.Get("chart")
@@ -178,19 +206,9 @@ func runUninstall(res http.ResponseWriter, req *http.Request) {
                        } else {
                                msg = "Successfully uninstalled release: " + chart
                        }
-                       if rapp.SecurityEnabled && rapp.Type == "provider" {
-                               // Remove istio objects for rapp
-                               fmt.Println("Removing istio services")
-                               _, err := http.Get("http://rapps-istio-mgr.default/remove?name=" + chartName)
-                               if err != nil {
-                                       msg = err.Error()
-                               }
-                               // remove keycloak client
-                               fmt.Println("Removing keycloak client")
-                               _, err = http.Get("http://rapps-keycloak-mgr.default/remove?realm=" + rapp.Realm + "&name=" + rapp.Client + "&role=" + rapp.Roles[0].Role)
-                               if err != nil {
-                                       msg = err.Error()
-                               }
+                       err := uninstallSecurity(rapp, chartName)
+                       if err != nil {
+                               msg = err.Error()
                        }
                }
                unregistrerRapp(chartName, rapp.Type)
@@ -204,6 +222,45 @@ func runUninstall(res http.ResponseWriter, req *http.Request) {
        res.Write(data)
 }
 
+func uninstallSecurity(rapp Rapp, chartName string) error {
+       var url string
+       var params string
+       role := rapp.Roles[0].Role
+       realm := rapp.Realm
+       client := rapp.Client
+       authenticator := rapp.Authenticator
+
+       if !rapp.SecurityEnabled {
+               return nil
+       }
+       if rapp.Type == "provider" {
+               // Remove istio objects for rapp
+               fmt.Println("Removing istio services")
+               _, err := http.Get("http://rapps-istio-mgr.default/remove-policy?name=" + chartName)
+               if err != nil {
+                       return err
+               }
+               // remove keycloak client
+               fmt.Println("Removing keycloak client")
+               url = "http://rapps-keycloak-mgr.default/remove?"
+               params = "name=" + client + "&realm=" + realm + "&role=" + role + "&authType=" + authenticator
+               url += params
+               _, err = http.Get(url)
+               if err != nil {
+                       return err
+               }
+       }
+       if rapp.Type == "invoker" {
+               // Remove istio objects for rapp
+               fmt.Println("Removing istio services")
+               _, err := http.Get("http://rapps-istio-mgr.default/remove-filter?name=" + chartName)
+               if err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
 func runList(res http.ResponseWriter, req *http.Request) {
        chartInfo := list()
        // create response binary data
@@ -480,7 +537,7 @@ func registrerRapp(chartName, chartType string) {
        id serial PRIMARY KEY,
        name VARCHAR ( 50 ) UNIQUE NOT NULL,
        type VARCHAR ( 50 ) NOT NULL,
-       created_on TIMESTAMP DEFAULT NOW() 
+       created_on TIMESTAMP DEFAULT NOW()
         );`
        _, err = db.Exec(createStmt)
        if err != nil {
index 19969db..e5cb1ea 100644 (file)
@@ -50,7 +50,7 @@ spec:
   template:
     metadata:
       labels:
-        app: rapps-helm-installer 
+        app: rapps-helm-installer
         version: v1
     spec:
       containers:
@@ -58,7 +58,7 @@ spec:
         image: ktimoney/rapps-helm-installer
         imagePullPolicy: IfNotPresent
         ports:
-        - containerPort: 9000 
+        - containerPort: 9000
         resources:
           limits:
             memory: 256Mi
@@ -67,7 +67,7 @@ spec:
             memory: 128Mi
             cpu: "80m"
       serviceAccountName: helm-app
-  replicas: 1 
+  replicas: 1
 ---
 apiVersion: v1
 kind: Service
@@ -79,7 +79,7 @@ spec:
     app: rapps-helm-installer
   ports:
     - protocol: TCP
-      port: 80 
-      targetPort: 9000 
-      nodePort: 31570 
+      port: 80
+      targetPort: 9000
+      nodePort: 31570
   type: NodePort
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)
 }
index 6003bb5..92d3f3a 100644 (file)
@@ -31,7 +31,7 @@ spec:
   template:
     metadata:
       labels:
-        app: rapps-istio-mgr 
+        app: rapps-istio-mgr
         version: v1
     spec:
       containers:
@@ -39,7 +39,7 @@ spec:
         image: ktimoney/rapps-istio-mgr
         imagePullPolicy: IfNotPresent
         ports:
-        - containerPort: 9000 
+        - containerPort: 9000
         resources:
           limits:
             memory: 256Mi
@@ -48,7 +48,7 @@ spec:
             memory: 128Mi
             cpu: "80m"
       serviceAccountName: helm-app
-  replicas: 1 
+  replicas: 1
 ---
 apiVersion: v1
 kind: Service
@@ -60,7 +60,7 @@ spec:
     app: rapps-istio-mgr
   ports:
     - protocol: TCP
-      port: 80 
-      targetPort: 9000 
-      nodePort: 31590 
+      port: 80
+      targetPort: 9000
+      nodePort: 31551
   type: NodePort
diff --git a/service-exposure/rapps-jwt.go b/service-exposure/rapps-jwt.go
new file mode 100644 (file)
index 0000000..d220458
--- /dev/null
@@ -0,0 +1,227 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   ========================LICENSE_END===================================
+//
+package main
+
+import (
+       "crypto/tls"
+       "crypto/x509"
+       "encoding/json"
+       "flag"
+       "fmt"
+       "io/ioutil"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       kubernetes "k8s.io/client-go/kubernetes"
+       "k8s.io/client-go/rest"
+       "net/http"
+       "net/url"
+       "rapps/utils/generatejwt"
+       "context"
+       "net"
+       "time"
+)
+
+type Jwttoken struct {
+       Access_token       string
+       Expires_in         int
+       Refresh_expires_in int
+       Refresh_token      string
+       Token_type         string
+       Not_before_policy  int
+       Session_state      string
+       Scope              string
+}
+
+var keycloakHost string
+var keycloakPort string
+var keycloakAlias string
+var realmName string
+var clientId string
+var namespace string
+var authenticator string
+var healthy bool = true
+var jwt Jwttoken
+
+const (
+       scope                 = "email"
+       client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
+)
+
+func getToken(res http.ResponseWriter, req *http.Request) {
+       var resp = &http.Response{}
+       var err error
+       authenticator = req.Header.Get("authenticator")
+       clientId = req.Header.Get("client")
+       realmName = req.Header.Get("realm")
+       namespace = req.Header.Get("ns")
+       keycloakUrl := "http://" + keycloakHost + ":" + keycloakPort + "/auth/realms/" + realmName + "/protocol/openid-connect/token"
+       fmt.Printf("Making token request to %s\n", keycloakUrl)
+       res.Header().Set("Content-type", "application/json")
+       res.Header().Set("Authorization", "")
+
+       if authenticator == "client-jwt" {
+               resp, err = getJwtToken(keycloakUrl, clientId)
+       } else if authenticator == "client-x509" {
+               resp, err = getx509Token(keycloakUrl, clientId)
+       } else {
+               resp, err = getSecretToken(keycloakUrl, clientId)
+       }
+
+       if err != nil {
+               fmt.Println(err)
+               res.WriteHeader(http.StatusInternalServerError)
+               res.Write([]byte(err.Error()))
+               panic("Something wrong with the credentials or url ")
+       }
+
+       defer resp.Body.Close()
+       body, err := ioutil.ReadAll(resp.Body)
+       json.Unmarshal([]byte(body), &jwt)
+       fmt.Printf("Token: %s\n", jwt.Access_token)
+
+       res.Header().Set("Authorization", "Bearer "+jwt.Access_token)
+       res.WriteHeader(http.StatusOK)
+       res.Write([]byte("Successfully retrieved JWT access token"))
+}
+
+func getJwtToken(keycloakUrl, clientId string) (*http.Response, error) {
+       var resp = &http.Response{}
+       var err error
+       client_assertion := getClientAssertion()
+
+       if jwt.Refresh_token != "" {
+               resp, err = http.PostForm(keycloakUrl, url.Values{"client_assertion_type": {client_assertion_type},
+                       "client_assertion": {client_assertion}, "grant_type": {"refresh_token"},
+                       "refresh_token": {jwt.Refresh_token}, "client_id": {clientId}, "scope": {scope}})
+       } else {
+               resp, err = http.PostForm(keycloakUrl, url.Values{"client_assertion_type": {client_assertion_type},
+                       "client_assertion": {client_assertion}, "grant_type": {"client_credentials"},
+                       "client_id": {clientId}, "scope": {scope}})
+       }
+
+       return resp, err
+}
+
+func getClientAssertion() string {
+       realm := "http://" + keycloakHost + ":" + keycloakPort + "/auth/realms/" + realmName
+       clientAssertion := generatejwt.CreateJWT("/certs/client.key", "", clientId, realm)
+       return clientAssertion
+}
+
+func getx509Token(keycloakUrl, clientId string) (*http.Response, error) {
+       var resp = &http.Response{}
+       var err error
+
+       client := getClient()
+       resp, err = client.PostForm(keycloakUrl, url.Values{"username": {""}, "password": {""}, "grant_type": {"password"}, "client_id": {clientId}, "scope": {scope}})
+
+       return resp, err
+}
+
+func getClient() *http.Client {
+       caCert, _ := ioutil.ReadFile("/certs/rootCA.crt")
+       caCertPool := x509.NewCertPool()
+       caCertPool.AppendCertsFromPEM(caCert)
+
+       cert, _ := tls.LoadX509KeyPair("/certs/client.crt", "/certs/client.key")
+
+       dialer := &net.Dialer{
+               Timeout:   30 * time.Second,
+               KeepAlive: 30 * time.Second,
+               DualStack: true,
+       }
+
+       client := &http.Client{
+               Transport: &http.Transport{
+                       DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
+                               fmt.Println("address original =", addr)
+                               if addr == keycloakAlias+":"+keycloakPort {
+                                       addr = keycloakHost + ":" + keycloakPort
+                                       fmt.Println("address modified =", addr)
+                               }
+                               return dialer.DialContext(ctx, network, addr)
+                       },
+                       TLSClientConfig: &tls.Config{
+                               RootCAs:      caCertPool,
+                               Certificates: []tls.Certificate{cert},
+                       },
+               },
+       }
+       return client
+}
+
+func getSecretToken(keycloakUrl, clientId string) (*http.Response, error) {
+       var resp = &http.Response{}
+       var err error
+
+       secretName := clientId + "-secret"
+       clientSecret := getSecret(secretName)
+       resp, err = http.PostForm(keycloakUrl,
+               url.Values{"client_secret": {clientSecret}, "grant_type": {"client_credentials"}, "client_id": {clientId}})
+
+       return resp, err
+}
+
+func getSecret(secretName string) string {
+       clientset := connectToK8s()
+       res, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
+       if err != nil {
+               fmt.Println(err.Error())
+       }
+       return string(res.Data["client_secret"])
+}
+
+func connectToK8s() *kubernetes.Clientset {
+       config, err := rest.InClusterConfig()
+       if err != nil {
+               fmt.Println("failed to create K8s config")
+       }
+
+       clientset, err := kubernetes.NewForConfig(config)
+       if err != nil {
+               fmt.Println("Failed to create K8s clientset")
+       }
+
+       return clientset
+}
+
+func health(res http.ResponseWriter, req *http.Request) {
+       if healthy {
+               res.WriteHeader(http.StatusOK)
+               res.Write([]byte("healthy"))
+       } else {
+               res.WriteHeader(http.StatusInternalServerError)
+               res.Write([]byte("unhealthy"))
+       }
+}
+
+func main() {
+       flag.StringVar(&keycloakHost, "keycloakHost", "istio-ingressgateway.istio-system", "Keycloak Host")
+       flag.StringVar(&keycloakPort, "keycloakPort", "80", "Keycloak Port")
+       flag.StringVar(&keycloakAlias, "keycloakAlias", "keycloak.oran.org", "Keycloak URL Alias")
+       flag.Parse()
+
+       healthHandler := http.HandlerFunc(health)
+       http.Handle("/health", healthHandler)
+       tokenHandler := http.HandlerFunc(getToken)
+       http.Handle("/token", tokenHandler)
+       http.ListenAndServe(":8888", nil)
+
+       ioutil.WriteFile("init.txt", []byte("Initialization done."), 0644)
+}
index 5fc92f4..35e503d 100644 (file)
@@ -17,7 +17,6 @@
 //   limitations under the License.
 //   ========================LICENSE_END===================================
 //
-
 package main
 
 import (
@@ -29,7 +28,6 @@ import (
        kubernetes "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/rest"
        "net/http"
-       "strings"
        "rapps/utils/pemtojwks"
 )
 
@@ -42,12 +40,13 @@ func createClient(res http.ResponseWriter, req *http.Request) {
        realmName := query.Get("realm")
        clientName := query.Get("name")
        role := query.Get("role")
+       authType := query.Get("authType")
        var msg string
-       msg, err := create(realmName, clientName, role)
+       msg, err := create(realmName, clientName, role, authType)
        if err != nil {
                msg = err.Error()
        }
-       if realmName != "x509" && realmName != "jwt" {
+       if authType == "client-secret" {
                createSecret(msg, clientName, realmName, role, namespace)
        }
        // create response binary data
@@ -61,12 +60,13 @@ func removeClient(res http.ResponseWriter, req *http.Request) {
        realmName := query.Get("realm")
        clientName := query.Get("name")
        role := query.Get("role")
+       authType := query.Get("authType")
 
        var msg string = "Removed keycloak " + clientName + " from " + realmName + " realm"
        remove(realmName, clientName)
-        if realmName != "x509" && realmName != "jwt" {
-               removeSecret(namespace, role)
-        }
+       if authType == "client-secret" {
+               removeSecret(namespace, role)
+       }
        // create response binary data
        data := []byte(msg) // slice of bytes
        // write `data` to response
@@ -81,7 +81,7 @@ func main() {
        http.ListenAndServe(":9000", nil)
 }
 
-func create(realmName, clientName, clientRoleName string) (string, error) {
+func create(realmName, clientName, clientRoleName, authType string) (string, error) {
        client := gocloak.NewClient("http://keycloak.default:8080")
        ctx := context.Background()
        token, err := client.LoginAdmin(ctx, "admin", "admin", "master")
@@ -122,7 +122,7 @@ func create(realmName, clientName, clientRoleName string) (string, error) {
                fmt.Println("Retrieved AuthenticationFlow id", flowId)
        }
 
-       newClient1 := gocloak.Client{
+       secretClient := gocloak.Client{
                ClientID:                  gocloak.StringP(clientName),
                Enabled:                   gocloak.BoolP(true),
                DirectAccessGrantsEnabled: gocloak.BoolP(true),
@@ -135,7 +135,7 @@ func create(realmName, clientName, clientRoleName string) (string, error) {
                        "client_credentials.use_refresh_token": "true"},
        }
 
-       newClient2 := gocloak.Client{
+       x509Client := gocloak.Client{
                ClientID:                  gocloak.StringP(clientName),
                Enabled:                   gocloak.BoolP(true),
                DirectAccessGrantsEnabled: gocloak.BoolP(true),
@@ -151,32 +151,32 @@ func create(realmName, clientName, clientRoleName string) (string, error) {
                AuthenticationFlowBindingOverrides: &map[string]string{"direct_grant": flowId},
        }
 
-        jwksString := pemtojwks.CreateJWKS("/certs/client_pub.key", "public", "/certs/client.crt") 
-       newClient3 := gocloak.Client{
-                ClientID:                  gocloak.StringP(clientName),
-                Enabled:                   gocloak.BoolP(true),
-                DirectAccessGrantsEnabled: gocloak.BoolP(true),
-                BearerOnly:                gocloak.BoolP(false),
-                PublicClient:              gocloak.BoolP(false),
-                ServiceAccountsEnabled:    gocloak.BoolP(true),
-                ClientAuthenticatorType:   gocloak.StringP("client-jwt"),
-                DefaultClientScopes:       &[]string{"email"},
-                Attributes: &map[string]string{"token.endpoint.auth.signing.alg": "RS256",
-                      "use.jwks.string": "true",
-                       "jwks.string": jwksString, 
-                      "use.refresh.tokens": "true",
-                       "client_credentials.use_refresh_token": "true",
+       jwksString := pemtojwks.CreateJWKS("/certs/client.crt")
+       jwtClient := gocloak.Client{
+               ClientID:                  gocloak.StringP(clientName),
+               Enabled:                   gocloak.BoolP(true),
+               DirectAccessGrantsEnabled: gocloak.BoolP(true),
+               BearerOnly:                gocloak.BoolP(false),
+               PublicClient:              gocloak.BoolP(false),
+               ServiceAccountsEnabled:    gocloak.BoolP(true),
+               ClientAuthenticatorType:   gocloak.StringP("client-jwt"),
+               DefaultClientScopes:       &[]string{"email"},
+               Attributes: &map[string]string{"token.endpoint.auth.signing.alg": "RS256",
+                       "use.jwks.string":                      "true",
+                       "jwks.string":                          jwksString,
+                       "use.refresh.tokens":                   "true",
+                       "client_credentials.use_refresh_token": "true",
                },
-        }
+       }
 
        var newClient gocloak.Client
-       if strings.HasPrefix(clientName, "x509") {
-               newClient = newClient2
-       } else if strings.HasPrefix(clientName, "jwt") {
-               newClient = newClient3
+       if authType == "client-x509" {
+               newClient = x509Client
+       } else if authType == "client-jwt" {
+               newClient = jwtClient
        } else {
-                newClient = newClient1
-        }
+               newClient = secretClient
+       }
 
        clientId, err := client.CreateClient(ctx, token.AccessToken, realmName, newClient)
        if err != nil {
@@ -204,7 +204,7 @@ func create(realmName, clientName, clientRoleName string) (string, error) {
                fmt.Println("Service Account user", *user.Username)
        }
 
-       if strings.HasPrefix(clientName, "x509") {
+       if authType == "client-x509" {
                newUser := gocloak.User{
                        ID:       gocloak.StringP(realmName + "user"),
                        Username: gocloak.StringP(realmName + "user"),
@@ -262,7 +262,7 @@ func create(realmName, clientName, clientRoleName string) (string, error) {
                fmt.Println("Client rolemapper added to client")
        }
 
-       if strings.HasPrefix(clientName, "x509") {
+       if authType == "client-x509" {
                clientRole := *newClient.ClientID + "." + clientRoleName
 
                clientroleMapper := gocloak.ProtocolMapperRepresentation{
@@ -336,7 +336,7 @@ func createSecret(clientSecret, clientName, realmName, role, namespace string) {
 }
 
 func remove(realmName, clientName string) {
-       adminClient := gocloak.NewClient("http://192.168.49.2:31560")
+       adminClient := gocloak.NewClient("http://keycloak.default:8080")
        ctx := context.Background()
        token, err := adminClient.LoginAdmin(ctx, "admin", "admin", "master")
        if err != nil {
index c2f14da..6774746 100644 (file)
@@ -31,7 +31,7 @@ spec:
   template:
     metadata:
       labels:
-        app: rapps-keycloak-mgr 
+        app: rapps-keycloak-mgr
         version: v1
     spec:
       containers:
@@ -39,7 +39,7 @@ spec:
         image: ktimoney/rapps-keycloak-mgr
         imagePullPolicy: IfNotPresent
         ports:
-        - containerPort: 9000 
+        - containerPort: 9000
         resources:
           limits:
             memory: 256Mi
@@ -58,7 +58,7 @@ spec:
            path: /var/rapps/certs
            type: DirectoryOrCreate
       serviceAccountName: helm-app
-  replicas: 1 
+  replicas: 1
 ---
 apiVersion: v1
 kind: Service
@@ -70,7 +70,7 @@ spec:
     app: rapps-keycloak-mgr
   ports:
     - protocol: TCP
-      port: 80 
-      targetPort: 9000 
+      port: 80
+      targetPort: 9000
       nodePort: 31600
   type: NodePort
diff --git a/service-exposure/rapps-rapp-helloworld-invoker1.go b/service-exposure/rapps-rapp-helloworld-invoker1.go
new file mode 100644 (file)
index 0000000..bfa5afa
--- /dev/null
@@ -0,0 +1,163 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   ========================LICENSE_END===================================
+//
+package main
+
+import (
+       "bytes"
+       "flag"
+       "fmt"
+       "github.com/prometheus/client_golang/prometheus"
+       "github.com/prometheus/client_golang/prometheus/promhttp"
+       "io/ioutil"
+       "net/http"
+       "strings"
+       "time"
+)
+
+
+var gatewayHost string
+var gatewayPort string
+var securityEnabled string
+var useGateway string
+var rapp string
+var methods string
+var healthy bool = true
+var ttime time.Time
+
+const (
+       namespace             = "istio-nonrtric"
+       scope                 = "email"
+       client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
+)
+
+var (
+       reqDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+               Name:    "rapp_http_request_duration_seconds",
+               Help:    "Duration of the last request call.",
+               Buckets: []float64{0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10},
+       }, []string{"app", "func", "handler", "method", "code"})
+       reqBytes = prometheus.NewSummaryVec(prometheus.SummaryOpts{
+               Name: "rapp_bytes_summary",
+               Help: "Summary of bytes transferred over http",
+       }, []string{"app", "func", "handler", "method", "code"})
+)
+
+
+func MakeRequest(client *http.Client, prefix string, method string, ch chan string) {
+       var service = strings.Split(prefix, "/")[1]
+       var gatewayUrl = "http://" + gatewayHost + ":" + gatewayPort
+       var jsonValue []byte = []byte{}
+       var restUrl string = ""
+
+       if securityEnabled != "true" {
+               gatewayUrl = "http://" + service + "." + namespace + ":80"
+               prefix = ""
+       }
+
+       restUrl = gatewayUrl + prefix
+       resp := &http.Response{}
+
+       timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
+               reqDuration.WithLabelValues("rapp-helloworld-invoker1", "MakeRequest", resp.Request.URL.Path, resp.Request.Method,
+                       resp.Status).Observe(v)
+       }))
+       defer timer.ObserveDuration()
+       fmt.Printf("Making get request to %s\n", restUrl)
+       req, err := http.NewRequest(method, restUrl, bytes.NewBuffer(jsonValue))
+       if err != nil {
+               fmt.Printf("Got error %s", err.Error())
+       }
+       req.Header.Set("Content-type", "application/json")
+
+       resp, err = client.Do(req)
+       if err != nil {
+               fmt.Printf("Got error %s", err.Error())
+       }
+
+       defer resp.Body.Close()
+       body, _ := ioutil.ReadAll(resp.Body)
+       reqBytes.WithLabelValues("rapp-helloworld-invoker1", "MakeRequest", req.URL.Path, req.Method,
+               resp.Status).Observe(float64(resp.ContentLength))
+
+       respString := string(body[:])
+       if respString == "RBAC: access denied" {
+               respString += " for " + service + " " + strings.ToLower(method) + " request"
+       }
+       fmt.Printf("Received response for %s %s request - %s\n", service, strings.ToLower(method), respString)
+       ch <- prefix + "," + method
+}
+
+func health(res http.ResponseWriter, req *http.Request) {
+       if healthy {
+               res.WriteHeader(http.StatusOK)
+               res.Write([]byte("healthy"))
+       } else {
+               res.WriteHeader(http.StatusInternalServerError)
+               res.Write([]byte("unhealthy"))
+       }
+}
+
+func main() {
+       ttime = time.Now()
+       time.Sleep(3 * time.Second)
+       prometheus.Register(reqDuration)
+       prometheus.Register(reqBytes)
+
+       flag.StringVar(&gatewayHost, "gatewayHost", "istio-ingressgateway.istio-system", "Gateway Host")
+       flag.StringVar(&gatewayPort, "gatewayPort", "80", "Gateway Port")
+       flag.StringVar(&useGateway, "useGateway", "Y", "Connect to services through API gateway")
+       flag.StringVar(&securityEnabled, "securityEnabled", "true", "Security is required to use this application")
+       flag.StringVar(&rapp, "rapp", "rapp-helloworld-provider", "Name of rapp to invoke")
+       flag.StringVar(&methods, "methods", "GET", "Methods to access application")
+       flag.Parse()
+
+       healthHandler := http.HandlerFunc(health)
+       http.Handle("/health", healthHandler)
+       http.Handle("/metrics", promhttp.Handler())
+       go func() {
+               http.ListenAndServe(":9000", nil)
+       }()
+
+       ioutil.WriteFile("init.txt", []byte("Initialization done."), 0644)
+
+       client := &http.Client{
+               Timeout: time.Second * 10,
+       }
+
+       ch := make(chan string)
+       var prefixArray []string = []string{"/" + rapp}
+       var methodArray []string = []string{methods}
+       for _, prefix := range prefixArray {
+               for _, method := range methodArray {
+                       go MakeRequest(client, prefix, method, ch)
+               }
+       }
+
+
+       for r := range ch {
+               go func(resp string) {
+                       time.Sleep(10 * time.Second)
+                       elements := strings.Split(resp, ",")
+                       prefix := elements[0]
+                       method := elements[1]
+                       MakeRequest(client, prefix, method, ch)
+               }(r)
+       }
+}
diff --git a/service-exposure/rapps-rapp-helloworld-invoker2.go b/service-exposure/rapps-rapp-helloworld-invoker2.go
new file mode 100644 (file)
index 0000000..93c6981
--- /dev/null
@@ -0,0 +1,163 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   ========================LICENSE_END===================================
+//
+package main
+
+import (
+       "bytes"
+       "flag"
+       "fmt"
+       "github.com/prometheus/client_golang/prometheus"
+       "github.com/prometheus/client_golang/prometheus/promhttp"
+       "io/ioutil"
+       "net/http"
+       "strings"
+       "time"
+)
+
+
+var gatewayHost string
+var gatewayPort string
+var securityEnabled string
+var useGateway string
+var rapp string
+var methods string
+var healthy bool = true
+var ttime time.Time
+
+const (
+       namespace             = "istio-nonrtric"
+       scope                 = "email"
+       client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
+)
+
+var (
+       reqDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+               Name:    "rapp_http_request_duration_seconds",
+               Help:    "Duration of the last request call.",
+               Buckets: []float64{0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10},
+       }, []string{"app", "func", "handler", "method", "code"})
+       reqBytes = prometheus.NewSummaryVec(prometheus.SummaryOpts{
+               Name: "rapp_bytes_summary",
+               Help: "Summary of bytes transferred over http",
+       }, []string{"app", "func", "handler", "method", "code"})
+)
+
+
+func MakeRequest(client *http.Client, prefix string, method string, ch chan string) {
+       var service = strings.Split(prefix, "/")[1]
+       var gatewayUrl = "http://" + gatewayHost + ":" + gatewayPort
+       var jsonValue []byte = []byte{}
+       var restUrl string = ""
+
+       if securityEnabled != "true" {
+               gatewayUrl = "http://" + service + "." + namespace + ":80"
+               prefix = ""
+       }
+
+       restUrl = gatewayUrl + prefix
+       resp := &http.Response{}
+
+       timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
+               reqDuration.WithLabelValues("rapp-helloworld-invoker2", "MakeRequest", resp.Request.URL.Path, resp.Request.Method,
+                       resp.Status).Observe(v)
+       }))
+       defer timer.ObserveDuration()
+       fmt.Printf("Making get request to %s\n", restUrl)
+       req, err := http.NewRequest(method, restUrl, bytes.NewBuffer(jsonValue))
+       if err != nil {
+               fmt.Printf("Got error %s", err.Error())
+       }
+       req.Header.Set("Content-type", "application/json")
+
+       resp, err = client.Do(req)
+       if err != nil {
+               fmt.Printf("Got error %s", err.Error())
+       }
+
+       defer resp.Body.Close()
+       body, _ := ioutil.ReadAll(resp.Body)
+       reqBytes.WithLabelValues("rapp-helloworld-invoker2", "MakeRequest", req.URL.Path, req.Method,
+               resp.Status).Observe(float64(resp.ContentLength))
+
+       respString := string(body[:])
+       if respString == "RBAC: access denied" {
+               respString += " for " + service + " " + strings.ToLower(method) + " request"
+       }
+       fmt.Printf("Received response for %s %s request - %s\n", service, strings.ToLower(method), respString)
+       ch <- prefix + "," + method
+}
+
+func health(res http.ResponseWriter, req *http.Request) {
+       if healthy {
+               res.WriteHeader(http.StatusOK)
+               res.Write([]byte("healthy"))
+       } else {
+               res.WriteHeader(http.StatusInternalServerError)
+               res.Write([]byte("unhealthy"))
+       }
+}
+
+func main() {
+       ttime = time.Now()
+       time.Sleep(4 * time.Second)
+       prometheus.Register(reqDuration)
+       prometheus.Register(reqBytes)
+
+       flag.StringVar(&gatewayHost, "gatewayHost", "istio-ingressgateway.istio-system", "Gateway Host")
+       flag.StringVar(&gatewayPort, "gatewayPort", "80", "Gateway Port")
+       flag.StringVar(&useGateway, "useGateway", "Y", "Connect to services through API gateway")
+       flag.StringVar(&securityEnabled, "securityEnabled", "true", "Security is required to use this application")
+       flag.StringVar(&rapp, "rapp", "rapp-helloworld-provider", "Name of rapp to invoke")
+       flag.StringVar(&methods, "methods", "GET", "Methods to access application")
+       flag.Parse()
+
+       healthHandler := http.HandlerFunc(health)
+       http.Handle("/health", healthHandler)
+       http.Handle("/metrics", promhttp.Handler())
+       go func() {
+               http.ListenAndServe(":9000", nil)
+       }()
+
+       ioutil.WriteFile("init.txt", []byte("Initialization done."), 0644)
+
+       client := &http.Client{
+               Timeout: time.Second * 10,
+       }
+
+       ch := make(chan string)
+       var prefixArray []string = []string{"/" + rapp}
+       var methodArray []string = []string{methods}
+       for _, prefix := range prefixArray {
+               for _, method := range methodArray {
+                       go MakeRequest(client, prefix, method, ch)
+               }
+       }
+
+
+       for r := range ch {
+               go func(resp string) {
+                       time.Sleep(10 * time.Second)
+                       elements := strings.Split(resp, ",")
+                       prefix := elements[0]
+                       method := elements[1]
+                       MakeRequest(client, prefix, method, ch)
+               }(r)
+       }
+}
diff --git a/service-exposure/rapps-rapp-helloworld-provider.go b/service-exposure/rapps-rapp-helloworld-provider.go
new file mode 100644 (file)
index 0000000..63d6493
--- /dev/null
@@ -0,0 +1,42 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   ========================LICENSE_END===================================
+//
+package main
+
+import (
+       "net/http"
+)
+
+// create a handler struct
+type HttpHandler struct{}
+
+// implement `ServeHTTP` method on `HttpHandler` struct
+func (h HttpHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
+       // create response binary data
+       data := []byte("Hello World Demo!") // slice of bytes
+       // write `data` to response
+       res.Write(data)
+}
+
+func main() {
+       // create a new handler
+       handler := HttpHandler{}
+       // listen and serve
+       http.ListenAndServe(":9000", handler)
+}
index 4dc7359..21c72c0 100644 (file)
@@ -17,7 +17,6 @@
 //   limitations under the License.
 //   ========================LICENSE_END===================================
 //
-
 package main
 
 import (
@@ -57,7 +56,7 @@ var role string
 var rapp string
 var methods string
 var healthy bool = true
-var ttime time.Time 
+var ttime time.Time
 var jwt Jwttoken
 
 const (
@@ -80,7 +79,7 @@ func getToken(secretName string) string {
                ttime = time.Now()
                ttime = ttime.Add(time.Second * time.Duration(jwt.Expires_in))
        }
-       return jwt.Access_token 
+       return jwt.Access_token
 }
 
 func getSecret(secretName string) (string, string, string) {
index 227f85e..4b5efd7 100644 (file)
@@ -17,7 +17,6 @@
 //   limitations under the License.
 //   ========================LICENSE_END===================================
 //
-
 package main
 
 import (
diff --git a/service-exposure/rapps-webhook.go b/service-exposure/rapps-webhook.go
new file mode 100644 (file)
index 0000000..242d622
--- /dev/null
@@ -0,0 +1,185 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   ========================LICENSE_END===================================
+//
+package main
+
+import (
+       "encoding/json"
+       "errors"
+       "flag"
+       "fmt"
+       "io/ioutil"
+       "k8s.io/api/admission/v1beta1"
+       v1 "k8s.io/api/core/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/runtime/serializer"
+       "log"
+       "net/http"
+)
+
+type ServerParameters struct {
+       port      string // webhook server port
+       certFile  string // path to the x509 cert
+       keyFile   string // path to the x509 private key
+       hostPath  string // path to the x509 private key
+}
+
+type patchOperation struct {
+       Op    string      `json:"op"`
+       Path  string      `json:"path"`
+       Value interface{} `json:"value,omitempty"`
+}
+
+var parameters ServerParameters
+
+var (
+       universalDeserializer = serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer()
+)
+
+func main() {
+       flag.StringVar(&parameters.port, "port", "8443", "Webhook server port.")
+       flag.StringVar(&parameters.certFile, "tlsCertFile", "/certs/tls.crt", "File containing the x509 certificate")
+       flag.StringVar(&parameters.keyFile, "tlsKeyFile", "/certs/tls.key", "File containing the x509 private key")
+       flag.StringVar(&parameters.hostPath, "hostPath", "/var/rapps/certs", "Host Path containing rapp cert files")
+       flag.Parse()
+
+       http.HandleFunc("/inject-sidecar", HandleSideCarInjection)
+       log.Fatal(http.ListenAndServeTLS(":"+parameters.port, parameters.certFile, parameters.keyFile, nil))
+}
+
+func HandleSideCarInjection(w http.ResponseWriter, r *http.Request) {
+
+       body, err := ioutil.ReadAll(r.Body)
+       err = ioutil.WriteFile("/tmp/request", body, 0644)
+       if err != nil {
+               panic(err.Error())
+       }
+
+       var admissionReviewReq v1beta1.AdmissionReview
+
+       if _, _, err := universalDeserializer.Decode(body, nil, &admissionReviewReq); err != nil {
+               w.WriteHeader(http.StatusBadRequest)
+               fmt.Errorf("Could not deserialize request: %v", err)
+       } else if admissionReviewReq.Request == nil {
+               w.WriteHeader(http.StatusBadRequest)
+               errors.New("Malformed admission review - request is empty")
+       }
+
+       fmt.Printf("Received Admission Review Request - Type: %v \t Event: %v \t Name: %v \n",
+               admissionReviewReq.Request.Kind,
+               admissionReviewReq.Request.Operation,
+               admissionReviewReq.Request.Name,
+       )
+
+       var pod v1.Pod
+
+       err = json.Unmarshal(admissionReviewReq.Request.Object.Raw, &pod)
+
+       if err != nil {
+               fmt.Errorf("Could not unmarshal pod from admission request: %v", err)
+       }
+
+       var patches []patchOperation
+
+       labels := pod.ObjectMeta.Labels
+       labels["sidecar-injection-webhook"] = "jwt-proxy"
+
+       patches = append(patches, patchOperation{
+               Op:    "add",
+               Path:  "/metadata/labels",
+               Value: labels,
+       })
+
+       var containers []v1.Container
+       containers = append(containers, pod.Spec.Containers...)
+       container := v1.Container{
+               Name:            "jwt-proxy",
+               Image:           "ktimoney/rapps-jwt",
+               ImagePullPolicy: v1.PullIfNotPresent,
+               Ports: []v1.ContainerPort{
+                       {
+                               Name:          "http",
+                               Protocol:      v1.ProtocolTCP,
+                               ContainerPort: 8888,
+                       },
+               },
+               VolumeMounts: []v1.VolumeMount{
+                       {
+                               Name:      "certsdir",
+                               MountPath: "/certs",
+                               ReadOnly:  true,
+                       },
+               },
+       }
+
+       containers = append(containers, container)
+       fmt.Println(containers)
+
+       patches = append(patches, patchOperation{
+               Op:    "add",
+               Path:  "/spec/containers",
+               Value: containers,
+       })
+
+       pathType := v1.HostPathDirectoryOrCreate
+       pathTypePtr := &pathType
+       var volumes []v1.Volume
+       volumes = append(volumes, pod.Spec.Volumes...)
+       volume := v1.Volume{
+               Name: "certsdir",
+               VolumeSource: v1.VolumeSource{
+                       HostPath: &v1.HostPathVolumeSource{
+                               Path: parameters.hostPath,
+                               Type: pathTypePtr,
+                       },
+               },
+       }
+       volumes = append(volumes, volume)
+       fmt.Println(volumes)
+
+       patches = append(patches, patchOperation{
+               Op:    "add",
+               Path:  "/spec/volumes",
+               Value: volumes,
+       })
+       fmt.Println(patches)
+
+       patchBytes, err := json.Marshal(patches)
+
+       if err != nil {
+               fmt.Errorf("Error occurred when trying to marshal JSON patch: %v", err)
+       }
+
+       admissionReviewResponse := v1beta1.AdmissionReview{
+               Response: &v1beta1.AdmissionResponse{
+                       UID:     admissionReviewReq.Request.UID,
+                       Allowed: true,
+               },
+       }
+
+       admissionReviewResponse.Response.Patch = patchBytes
+
+       bytes, err := json.Marshal(&admissionReviewResponse)
+       if err != nil {
+               fmt.Errorf("Error occurred when trying to marshal Aadmission Review response: %v", err)
+       }
+
+       w.Write(bytes)
+
+}
diff --git a/service-exposure/rapps-webhook.yaml b/service-exposure/rapps-webhook.yaml
new file mode 100644 (file)
index 0000000..1b51317
--- /dev/null
@@ -0,0 +1,115 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+---
+############################################################
+# TLS certificate for OPA admission controller.
+############################################################
+apiVersion: v1
+kind: Secret
+metadata:
+  name: webhook-cert
+  namespace: default
+type: Opaque
+data:
+  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVMekNDQXhlZ0F3SUJBZ0lVUTZFV1pIK3RQdTk0WmEzeWp6STFFbGNBcTdrd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1RURUxNQWtHQTFVRUJoTUNTVVV4RURBT0JnTlZCQWdUQjFkbFltaHZiMnN4RHpBTkJnTlZCQWNUQmtSMQpZbXhwYmpFTU1Bb0dBMVVFQ2hNRFJWTlVNUTB3Q3dZRFZRUUxFd1JQY21GdU1CNFhEVEl5TURreU1EQTRNRGt3Ck1Gb1hEVFF5TURreE5UQTRNRGt3TUZvd1RURUxNQWtHQTFVRUJoTUNTVVV4RURBT0JnTlZCQWdUQjFkbFltaHYKYjJzeER6QU5CZ05WQkFjVEJrUjFZbXhwYmpFTU1Bb0dBMVVFQ2hNRFJWTlVNUTB3Q3dZRFZRUUxFd1JQY21GdQpNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQW0zdUdEYnVwQkhjV3lockZ1TjdrCkFRN3hZeW05NGVjcjJZOE5mbHFtTDU2NG9YTzlic09uaG85czVtLzdiNUFTUlZ4aTJlUFltTGg4ZmlxL3hZaDgKZEo5M3ErWm8vZU9zUElER3BFTlBCQjhqL3AwNHkyckJwN2IwZk5PdTQ2dFB1YUNMRzR6ZEZoSkgyWU5FbGxnbQpqYWtvTThPcTBCZGYrejJlSWlBYWYxQTN1bTY0czJaR1pnR2hSdnhkYW1zVFhLNm1hNFd4OXBhMHlkdC93dnJtCm1SUThWOUlDNDhOS2QveTBpUmh3M2pRNzZUb05NWWFiUk9LTE1jNjMwVXZtL2NuV0dZNjZNeFVoeEhLUWY4SE4KTGp3U1VGRzlWYmVBYXQwcktoSkw2L21Eb3dpbzFRaXhoK25lazRXdm41cGFiZzlLakRWUnRja0NXS0toeUhFTAovUUlEQVFBQm80SUJCVENDQVFFd0RnWURWUjBQQVFIL0JBUURBZ1dnTUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGCkJ3TUJCZ2dyQmdFRkJRY0RBakFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCVGFTU1luVDA3L3ZDMmsKTDk0NmhmRVFzemN6b1RDQm9nWURWUjBSQklHYU1JR1hnaDVxZDNRdGNISnZlSGt0WVdSdGFYTnphVzl1TFdOdgpiblJ5YjJ4c1pYS0NPR3AzZEMxd2NtOTRlUzFoWkcxcGMzTnBiMjR0WTI5dWRISnZiR3hsY2k1a1pXWmhkV3gwCkxuTjJZeTVqYkhWemRHVnlMbXh2WTJGc2dpcHFkM1F0Y0hKdmVIa3RZV1J0YVhOemFXOXVMV052Ym5SeWIyeHMKWlhJdVpHVm1ZWFZzZEM1emRtT0NDV3h2WTJGc2FHOXpkSWNFZndBQUFUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQwpBUUVBU0EzV1VmbG9Ia0NIaU1TZ2VQSkVaUXdHN0tZSnJUQjByS25tYmFFSzloZnNveWlXcWs2WTl5RjFsMFVFCjBvQTdiRUZBRWh6S0VkcGxXOHRrQ1ZwaGxQZ0FBbktPU0dhYlVUam9KYURsWDBDRS9oNE5RaTlmOHVKT0ZkaVEKc3JRcXZCZWthUzNOd2ZIVHBTdFRnSEs1bEovMjUxenJ1VVZ0VTBERWpIQ1BYUks2S09uUmlNYktCSFBDNmoybQpmV29zdC9NYWJhbUlvOHlIdjZXaHNTbXhDODlEZ1BXa3RXM01QOXFEUjlTVWQzWk5BdWZKU0hEeDkxWEN6L2JpClRFZjRrRE1GRnVsMW5UUzBXTlhVUEV1MnR0SWxmMDBsZS91VHVNVUxOZ3V3Umlmc2tPSmFJcUVBc2NxWmtxdEMKQW5EMGdnV01QMEpCL1k1eGZTM1ZPLzBPVVE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
+  tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBbTN1R0RidXBCSGNXeWhyRnVON2tBUTd4WXltOTRlY3IyWThOZmxxbUw1NjRvWE85CmJzT25obzlzNW0vN2I1QVNSVnhpMmVQWW1MaDhmaXEveFloOGRKOTNxK1pvL2VPc1BJREdwRU5QQkI4ai9wMDQKeTJyQnA3YjBmTk91NDZ0UHVhQ0xHNHpkRmhKSDJZTkVsbGdtamFrb004T3EwQmRmK3oyZUlpQWFmMUEzdW02NApzMlpHWmdHaFJ2eGRhbXNUWEs2bWE0V3g5cGEweWR0L3d2cm1tUlE4VjlJQzQ4TktkL3kwaVJodzNqUTc2VG9OCk1ZYWJST0tMTWM2MzBVdm0vY25XR1k2Nk14VWh4SEtRZjhITkxqd1NVRkc5VmJlQWF0MHJLaEpMNi9tRG93aW8KMVFpeGgrbmVrNFd2bjVwYWJnOUtqRFZSdGNrQ1dLS2h5SEVML1FJREFRQUJBb0lCQUFhWm9jRW5mQzlDVnVkUgpaNTlIWnVwY2xnYWRtUC9qN2txWDlmeXRJR3paRWdGWWhtd1RSaU5DSjE5STFhV1F1aFhUckNhUHMzd1lLTUM2ClU5V3d5NGV2MVVhb3kwQXJ6LzNwZ1lVcmpra2dnVWlucCtlS3FwblIvR0xvSVg1c29UL0IvdVcyZnhRV3hwSUgKTG53clZjZWhyS0UxNXlSYU9hclNuTW5hRHdYa2N1ZlF4enFLR1E2aFZZUGFGSk9JUXJQWmZXei84b2ZpWThBbwprSlZjSG1uOTZNLzZxRWhTbVZHcmc5M1BtYjJkUmNyc2hDblRCY2g5dDNuNnV4WGxKcmx0dG9lR1piTDB3Y3M0Ck9Wc2NDY043NEx3OGozSkdXeDg2QmVLT3ZORlJKajh3ajdxcGhsTW5hNjUxTmd6UE41eXlIR1IzWVhXU1lxSFcKMW9BRFFva0NnWUVBekN5ZlJjRTdMMEtsVGY4VmQ5cjZpRjhwcktBV0xSeXRZQTJjUUdSYWZHZlZYenJ4TnNBRwpGVlZlL2RabzVRa0I5NjlkKzRudDV5OUQzMWhYUGRNa0w0UWlWaHBuSE5zSzg4RVpuVXkxTkRBVCtJdEorY0VmCi9UaHRKa2Z4VGVXb1p6cmhIU1kxb2theFpzMWJ6bFpUNzFMTnBRTUs3bDBzc2hCVUdreklCME1DZ1lFQXd2TGcKcHhlWEtMMHVxNExWQVdMVEtyb2ttdmdIOG80QWpiekZLUnVTUTdlL3pVdXNVbVlZdFdMMEVqcGZXSTdNdXhrUwpjZUJiRmduakl5S3lGbDZTQ1BPaCs0N09EdlRNMDBpTGdoTnpOalVJbkE5RGJCV2ZURFVYd3ZHSDdhUGJ1OEVuCjFFUW1Wc2l5bC80SG1nK055WWJ5Q29WU1ZPZEJrQit1d0VYeFM3OENnWUFGOE9wMWlpamh1Q3U5T0VYMHBkK1MKWmtwOUptOWV3cTNjMUtpT1N4MUM3M2FLL2RrVkFjTnJqWDlsSFg4UjR4QTJsOWpCUUFNM0xlM29xdFpuQ3lUTAphU25pbllRUWwrTWFzcXkvSWdOSDBIcFVTaUZON2l1ekg1ZzFlL1J1a3RjeW9jajVJeXArWFZZK0tvMllWSFMrCnl3Y0czUzdOUHRMVkg1cUM1V2NRcHdLQmdBYUp5c3NQMlh2K1RGQm9ST2lVL2V3UzdpTmNhamZTVjJacGpGdEMKbDNjNTlHN1lPT0ZTbDBXT0dnMTZjN1F1cGVNb2hodlhvSFp1d25WdE5uZlZtQ1JBdDVBT1RBN29XdTVESXBxcwpPRkw3R0Z6VGpqbFR5Rkh2L2VvRjI3ODJuYW9BWW11V0ZZc1hsQlhRNlVSYmZTL2pITDhKbGFkUFVqMlpNbTAwCmExRlZBb0dBVlRReHNXNDJXWkRIQVExZC8vSzNXYTBQS0dWWmhHbkYxNFQzUlB3VDVDcGVKbmhhQ0QvVzh1VFQKSHBUUi8ySTY2RFQ5UjI2SlZReERoemNaa3dmR3krQVNoQ3BSb2FJZERGdjI1TS9EVGoxT2dUMUZpNm91ZjlzMgpVdFdkSEo1NlJ3cUhuRlptcnB2T3V4bGgwUWdQUHo3ZTg3dzBJMlpJQi9tRzY0Y2NHMlk9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: webhook-app
+  namespace: default
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: webhook-app
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+  - kind: ServiceAccount
+    name: webhook-app
+    namespace: default
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: jwt-proxy-admission-controller-deployment
+  namespace: default
+  labels:
+    app: jwt-proxy-admission-controller
+spec:
+  selector:
+    matchLabels:
+      app: jwt-proxy-admission-controller
+  template:
+    metadata:
+      labels:
+        app: jwt-proxy-admission-controller
+        version: v1
+    spec:
+      serviceAccountName: webhook-app
+      containers:
+      - name: jwt-proxy-admission-controller
+        image: ktimoney/rapps-webhook
+        imagePullPolicy: IfNotPresent
+        command: ["/app/rapps-webhook"]
+        args: [
+                "-port", "8443",
+                "-tlsCertFile", "/certs/tls.crt",
+                "-tlsKeyFile", "/certs/tls.key",
+                "-hostPath", "/var/rapps/certs"
+              ]
+        ports:
+        - containerPort: 8443
+        resources:
+          limits:
+            memory: 256Mi
+            cpu: "250m"
+          requests:
+            memory: 128Mi
+            cpu: "80m"
+        volumeMounts:
+          - readOnly: true
+            mountPath: /certs
+            name: webhook-cert
+      volumes:
+        - name: webhook-cert
+          secret:
+            secretName: webhook-cert
+  replicas: 1
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: jwt-proxy-admission-controller
+  namespace: default
+spec:
+  selector:
+    app: jwt-proxy-admission-controller
+  ports:
+    - protocol: TCP
+      port: 443
+      targetPort: 8443
+      nodePort: 30570
+  type: NodePort
+---
index c1d07a2..c26f9ae 100644 (file)
@@ -30,23 +30,14 @@ REFRESH_TOKEN=""
 
 function get_token
 {
-    local prefix="${1}" 
+    local prefix="${1}"
     url="http://192.168.49.2:31560/auth/realms"
-    #     echo $url
          TOKEN=$(curl -s -X POST $url/provider/protocol/openid-connect/token -H \
                 "Content-Type: application/x-www-form-urlencoded" -d client_secret=OwTCeahULA21G5TfEVMLG1iMloGiyH3i \
-                -d 'grant_type=client_credentials' -d client_id=provider-cli) 
+                -d 'grant_type=client_credentials' -d client_id=provider-cli)
        echo "TOKEN: $TOKEN"
         ACCESS_TOKEN=$(echo $TOKEN | jq -r '.access_token')
-       #echo "ACCESS_TOKEN: $ACCESS_TOKEN"
         REFRESH_TOKEN=$(echo $TOKEN | jq -r '.refresh_token')
-       #echo "REFRESH_TOKEN: $REFRESH_TOKEN"
-        # TOKEN2=$(curl -s -X POST $url/provider/protocol/openid-connect/token -H \
-       #        "Content-Type: application/x-www-form-urlencoded" -d client_secret= \
-       #        -d refresh_token=$REFRESH_TOKEN \
-       #        -d 'grant_type=refresh_token' -d client_id=provider-cli) 
-       #echo "TOKEN2 = $TOKEN2"
-        #ACCESS_TOKEN=""
     echo $ACCESS_TOKEN
 }
 
index f4281c9..f1dc515 100644 (file)
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=========================================================
 #
+export host=$(minikube ip)
 
-kubectl create -f chartmuseum.yaml 
+echo "Deploying applications..."
+echo "-------------------------"
+kubectl create -f chartmuseum.yaml
 kubectl create -f rapps-keycloak-mgr.yaml
 kubectl create -f  rapps-istio-mgr.yaml
 kubectl create -f  rapps-helm-installer.yaml
+kubectl create -f rapps-webhook.yaml
+
+echo ""
+echo "Waiting for pods to start..."
+echo "----------------------------"
+kubectl wait deployment -n default chartmuseum-deployment --for=condition=available --timeout=90s
+kubectl wait deployment -n default rapps-keycloak-mgr-deployment --for=condition=available --timeout=90s
+kubectl wait deployment -n default rapps-istio-mgr-deployment --for=condition=available --timeout=90s
+kubectl wait deployment -n default rapps-helm-installer-deployment --for=condition=available --timeout=90s
+kubectl wait deployment -n default jwt-proxy-admission-controller-deployment --for=condition=available --timeout=90s
+
+echo ""
+echo "Configure sidecar injection..."
+echo "----------------------------"
+kubectl create -f MutatingWebhookConfiguration.yaml
+
+echo ""
+echo "Checking pod status..."
+echo "----------------------"
+kubectl get pods -n default
index 86f22ef..fa67b13 100644 (file)
 # ============LICENSE_END=========================================================
 #
 
+export host=$(minikube ip)
+
+echo "Undeploying applications..."
+echo "---------------------------"
+curl http://$host:31570/uninstall?chart=rapp-helloworld-invoker1
+echo ""
+sleep 2
+curl http://$host:31570/uninstall?chart=rapp-helloworld-invoker2
+echo ""
+sleep 2
+curl http://$host:31570/uninstall?chart=rapp-helloworld-provider
+echo ""
+
 kubectl delete -f  rapps-helm-installer.yaml
 kubectl delete -f  rapps-istio-mgr.yaml
 kubectl delete -f rapps-keycloak-mgr.yaml
 kubectl delete -f chartmuseum.yaml
+kubectl delete -f rapps-webhook.yaml
+kubectl delete -f MutatingWebhookConfiguration.yaml
diff --git a/service-exposure/templates/AuthorizationPolicy-template.txt b/service-exposure/templates/AuthorizationPolicy-template.txt
new file mode 100644 (file)
index 0000000..0899475
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+apiVersion: "security.istio.io/v1beta1"
+kind: "AuthorizationPolicy"
+metadata:
+  name: "{{.Name}}-policy"
+  namespace: {{.Namespace}}
+spec:
+  selector:
+    matchLabels:
+      app.kubernetes.io/instance: {{.Name}}
+  action: ALLOW
+  rules:
+  - from:
+    - source:
+        requestPrincipals: ["http://istio-ingressgateway.istio-system:80/auth/realms/{{.Realm}}/"]
+  - to:
+    - operation:
+        methods: ["{{.Method}}"]
+        paths: ["/{{.Name}}"]
+    when:
+    - key: request.auth.claims[clientRole]
+      values: ["{{.Role}}"]
diff --git a/service-exposure/templates/EnvoyFilter-template.txt b/service-exposure/templates/EnvoyFilter-template.txt
new file mode 100644 (file)
index 0000000..f023fa6
--- /dev/null
@@ -0,0 +1,90 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+apiVersion: networking.istio.io/v1alpha3
+kind: EnvoyFilter
+metadata:
+  name: {{.Name}}-outbound-filter
+  namespace: {{.Namespace}}
+spec:
+  workloadSelector:
+    labels:
+      app.kubernetes.io/name: {{.Name}}
+  configPatches:
+    # The first patch adds the lua filter to the listener/http connection manager
+  - applyTo: HTTP_FILTER
+    match:
+      context: SIDECAR_OUTBOUND
+      listener:
+        filterChain:
+          filter:
+            name: "envoy.filters.network.http_connection_manager"
+            subFilter:
+              name: "envoy.filters.http.router"
+    patch:
+      operation: INSERT_BEFORE
+      value: # lua filter specification
+        name: envoy.lua
+        typed_config:
+          "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
+          inlineCode: |
+            function envoy_on_request(request_handle)
+              local uri = request_handle:headers():get(":path")
+              local method = request_handle:headers():get(":method")
+              if (method ~= "POST" and uri ~= "/auth/realms/{{.Realm}}/protocol/openid-connect/token")
+              then
+               -- Make an HTTP call to an upstream host with the following headers, body, and timeout.
+               local headers, body = request_handle:httpCall(
+                "jwt_cluster",
+                {
+                 [":method"] = "GET",
+                 [":path"] = "/token",
+                 [":authority"] = "jwt-proxy",
+                 ["realm"] = "{{.Realm}}",
+                 ["client"] = "{{.Client}}",
+                 ["authenticator"] = "{{.Authenticator}}",
+                 ["ns"] = "{{.Namespace}}"
+                },
+               "jwt call",
+               5000)
+               if (headers["authorization"] ~= nil)
+               then
+                   request_handle:headers():add("authorization", headers["authorization"])
+               end
+              end
+            end
+  - applyTo: CLUSTER
+    match:
+      context: SIDECAR_OUTBOUND
+    patch:
+      operation: ADD
+      value: # cluster specification
+        name: jwt_cluster
+        type: STRICT_DNS
+        connect_timeout: 60s
+        lb_policy: ROUND_ROBIN
+        load_assignment:
+          cluster_name: jwt_cluster
+          endpoints:
+          - lb_endpoints:
+            - endpoint:
+                address:
+                  socket_address:
+                    address: 0.0.0.0
+                    port_value: 8888
diff --git a/service-exposure/templates/Gateway-template.txt b/service-exposure/templates/Gateway-template.txt
new file mode 100644 (file)
index 0000000..594a627
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+apiVersion: networking.istio.io/v1beta1
+kind: Gateway
+metadata:
+  name: nonrtric-istio-{{.Name}}-gateway
+  namespace: {{.Namespace}}
+spec:
+  selector:
+    istio: ingressgateway # use Istio gateway implementation
+  servers:
+  - port:
+      number: 80
+      name: http
+      protocol: HTTP
+    hosts:
+    - "*"
diff --git a/service-exposure/templates/RequestAuthentication-template.txt b/service-exposure/templates/RequestAuthentication-template.txt
new file mode 100644 (file)
index 0000000..5fbdbbb
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+apiVersion: security.istio.io/v1beta1
+kind: RequestAuthentication
+metadata:
+  name: "jwt-{{.Name}}"
+  namespace: {{.Namespace}}
+spec:
+  selector:
+    matchLabels:
+      app.kubernetes.io/instance: {{.Name}}
+  jwtRules:
+  - issuer: "http://istio-ingressgateway.istio-system:80/auth/realms/{{.Realm}}"
+    jwksUri: "http://keycloak.default:8080/auth/realms/{{.Realm}}/protocol/openid-connect/certs"
diff --git a/service-exposure/templates/VirtualService-template.txt b/service-exposure/templates/VirtualService-template.txt
new file mode 100644 (file)
index 0000000..93be9cd
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+apiVersion: networking.istio.io/v1beta1
+kind: VirtualService
+metadata:
+  name: nonrtric-istio-{{.Name}}-vs
+  namespace: {{.Namespace}}
+spec:
+  hosts:
+  - "*"
+  gateways:
+  - nonrtric-istio-{{.Name}}-gateway
+  http:
+  - name: "{{.Name}}-routes"
+    match:
+    - uri:
+        prefix: "/{{.Name}}"
+    route:
+    - destination:
+        port:
+          number: 80
+        host: {{.Name}}.{{.Namespace}}.svc.cluster.local
diff --git a/service-exposure/undeploy_rapp.sh b/service-exposure/undeploy_rapp.sh
new file mode 100644 (file)
index 0000000..5e37e17
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2022 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+export host=$(minikube ip)
+
+if [ -z "$1" ]
+  then
+    echo "No argument supplied"
+    exit 1
+fi
+
+rapp=$1
+
+curl http://$host:31570/uninstall?chart=$rapp
+echo ""
+
+kubectl wait deployment -n istio-nonrtric $rapp --for=delete --timeout=90s
+
+kubectl get pods -n istio-nonrtric
diff --git a/service-exposure/utils/generatejwt/generatejwt.go b/service-exposure/utils/generatejwt/generatejwt.go
new file mode 100644 (file)
index 0000000..7157f82
--- /dev/null
@@ -0,0 +1,184 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   ========================LICENSE_END===================================
+//
+package generatejwt
+
+import (
+       "crypto/rsa"
+       "crypto/x509"
+       "encoding/pem"
+       "fmt"
+       "github.com/dgrijalva/jwt-go"
+       "io/ioutil"
+       "log"
+       "time"
+)
+
+type JWT struct {
+       privateKey []byte
+       publicKey  []byte
+}
+
+func NewJWT(privateKey []byte, publicKey []byte) JWT {
+       return JWT{
+               privateKey: privateKey,
+               publicKey:  publicKey,
+       }
+}
+
+func readFile(file string) []byte {
+       key, err := ioutil.ReadFile(file)
+       if err != nil {
+               log.Fatalln(err)
+       }
+       return key
+}
+
+func (j JWT) createWithKey(ttl time.Duration, content interface{}, client, realm string) (string, error) {
+       key, err := jwt.ParseRSAPrivateKeyFromPEM(j.privateKey)
+       if err != nil {
+               return "", fmt.Errorf("create: parse key: %w", err)
+       }
+
+       now := time.Now().UTC()
+
+       claims := make(jwt.MapClaims)
+       claims["dat"] = content             // Our custom data.
+       claims["exp"] = now.Add(ttl).Unix() // The expiration time after which the token must be disregarded.
+       claims["iat"] = now.Unix()          // The time at which the token was issued.
+       claims["nbf"] = now.Unix()          // The time before which the token must be disregarded.
+       claims["jti"] = "myJWTId" + fmt.Sprint(now.UnixNano())
+       claims["sub"] = client
+       claims["iss"] = client
+       claims["aud"] = realm
+
+       token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
+       tokenString, err := token.SignedString(key)
+       if err != nil {
+               return "", fmt.Errorf("create: sign token: %w", err)
+       }
+
+       return tokenString, nil
+}
+
+func createWithSecret(ttl time.Duration, content interface{}, client, realm, secret string) (string, error) {
+       now := time.Now().UTC()
+
+       claims := make(jwt.MapClaims)
+       claims["dat"] = content             // Our custom data.
+       claims["exp"] = now.Add(ttl).Unix() // The expiration time after which the token must be disregarded.
+       claims["iat"] = now.Unix()          // The time at which the token was issued.
+       claims["nbf"] = now.Unix()          // The time before which the token must be disregarded.
+       claims["jti"] = "myJWTId" + fmt.Sprint(now.UnixNano())
+       claims["sub"] = client
+       claims["iss"] = client
+       claims["aud"] = realm
+
+       token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
+       if err != nil {
+               return "", fmt.Errorf("create: sign token: %w", err)
+       }
+
+       return token, nil
+}
+
+func (j JWT) Validate(token string) (interface{}, error) {
+       key, err := jwt.ParseRSAPublicKeyFromPEM(j.publicKey)
+       if err != nil {
+               return "", fmt.Errorf("validate: parse key: %w", err)
+       }
+
+       tok, err := jwt.Parse(token, func(jwtToken *jwt.Token) (interface{}, error) {
+               if _, ok := jwtToken.Method.(*jwt.SigningMethodRSA); !ok {
+                       return nil, fmt.Errorf("unexpected method: %s", jwtToken.Header["alg"])
+               }
+
+               return key, nil
+       })
+       if err != nil {
+               return nil, fmt.Errorf("validate: %w", err)
+       }
+
+       claims, ok := tok.Claims.(jwt.MapClaims)
+       if !ok || !tok.Valid {
+               return nil, fmt.Errorf("validate: invalid")
+       }
+
+       return claims["dat"], nil
+}
+
+func createPublicKeyFromPrivateKey(privkey_bytes []byte) []byte {
+       block, _ := pem.Decode([]byte(privkey_bytes))
+       var privateKey *rsa.PrivateKey
+       pkcs1, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+       if err != nil {
+               pkcs8, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+               privateKey = pkcs8.(*rsa.PrivateKey)
+               if err != nil {
+                       log.Fatal(err)
+               }
+       } else {
+               privateKey = pkcs1
+       }
+
+       publicKey := &privateKey.PublicKey
+
+       pubkey_bytes, err := x509.MarshalPKIXPublicKey(publicKey)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       pubkey_pem := pem.EncodeToMemory(
+               &pem.Block{
+                       Type:  "PUBLIC KEY",
+                       Bytes: pubkey_bytes,
+               },
+       )
+       return pubkey_pem
+}
+
+func CreateJWT(privateKeyFile, secret, client, realm string) string {
+       if secret == "" {
+               prvKey := readFile(privateKeyFile)
+               pubKey := createPublicKeyFromPrivateKey(prvKey)
+
+               jwtToken := NewJWT(prvKey, pubKey)
+
+               // 1. Create a new JWT token.
+               tok, err := jwtToken.createWithKey(time.Hour, "Can be anything", client, realm)
+               if err != nil {
+                       log.Fatalln(err)
+               }
+
+               // 2. Validate an existing JWT token.
+               _, err = jwtToken.Validate(tok)
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               return tok
+       } else {
+               // 1. Create a new JWT token.
+               tok, err := createWithSecret(time.Hour, "Can be anything", client, realm, secret)
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               return tok
+       }
+
+}
diff --git a/service-exposure/utils/pemtojwks/pemtojwks.go b/service-exposure/utils/pemtojwks/pemtojwks.go
new file mode 100644 (file)
index 0000000..6317843
--- /dev/null
@@ -0,0 +1,133 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   ========================LICENSE_END===================================
+//
+package pemtojwks
+
+import (
+       "crypto/rsa"
+       "crypto/sha1"
+       "crypto/x509"
+       "encoding/base64"
+       "encoding/json"
+       "encoding/pem"
+       "fmt"
+       "golang.org/x/crypto/ssh"
+       "io/ioutil"
+       "math/big"
+)
+
+type Jwks struct {
+       Keys []Key `json:"keys"`
+}
+type Key struct {
+       Kid string `json:"kid,omitempty"`
+       Kty string `json:"kty"`
+       Use string `json:"use"`
+       N   string `json:"n"`
+       E   string `json:"e"`
+       X5c []string `json:"x5c"`
+       X5t string `json:"x5t"`
+}
+
+func getKeyFromPrivate(key []byte) *rsa.PublicKey {
+       parsed, err := ssh.ParseRawPrivateKey(key)
+       if err != nil {
+               fmt.Println(err)
+       }
+
+       // Convert back to an *rsa.PrivateKey
+       privateKey := parsed.(*rsa.PrivateKey)
+
+       publicKey := &privateKey.PublicKey
+       return publicKey
+}
+
+func getKeyFromPublic(key []byte) *rsa.PublicKey {
+       pubPem, _ := pem.Decode(key)
+
+       parsed, err := x509.ParsePKIXPublicKey(pubPem.Bytes)
+       if err != nil {
+               fmt.Println("Unable to parse RSA public key", err)
+       }
+
+       // Convert back to an *rsa.PublicKey
+       publicKey := parsed.(*rsa.PublicKey)
+
+       return publicKey
+}
+
+func getCert(cert []byte) *x509.Certificate {
+       certPem, _ := pem.Decode(cert)
+       if certPem == nil {
+               panic("Failed to parse pem file")
+       }
+
+       // pass cert bytes
+       certificate, err := x509.ParseCertificate(certPem.Bytes)
+       if err != nil {
+               fmt.Println("Unable to parse Certificate", err)
+       }
+
+       return certificate
+}
+
+func getPublicKeyFromCert(cert_bytes []byte) *rsa.PublicKey {
+        block, _ := pem.Decode([]byte(cert_bytes))
+        var cert *x509.Certificate
+        cert, _ = x509.ParseCertificate(block.Bytes)
+        rsaPublicKey := cert.PublicKey.(*rsa.PublicKey)
+
+        return rsaPublicKey
+}
+
+func CreateJWKS(certFile string) string {
+       var publicKey *rsa.PublicKey
+
+       cert, err := ioutil.ReadFile(certFile)
+       if err != nil {
+               fmt.Println(err)
+       }
+       publicKey = getPublicKeyFromCert(cert)
+
+       certificate := getCert(cert)
+       // generate fingerprint with sha1
+       // you can also use md5, sha256, etc.
+       fingerprint := sha1.Sum(certificate.Raw)
+
+
+       jwksKey := Key{
+               Kid: "SIGNING_KEY",
+               Kty: "RSA",
+               Use: "sig",
+               N: base64.RawStdEncoding.EncodeToString(publicKey.N.Bytes()),
+               E: base64.RawStdEncoding.EncodeToString(big.NewInt(int64(publicKey.E)).Bytes()),
+               X5c: []string{base64.RawStdEncoding.EncodeToString(certificate.Raw)},
+               X5t: base64.RawStdEncoding.EncodeToString(fingerprint[:]),
+       }
+       jwksKeys := []Key{jwksKey}
+       jwks := Jwks{jwksKeys}
+
+       jwksJson, err := json.Marshal(jwks)
+       if err != nil {
+               fmt.Println(err)
+               return err.Error()
+       }
+       return string(jwksJson)
+
+}