diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 3e8af34..d2c9b20 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -2,9 +2,9 @@ name: Pylint and Pytest on: push: - branches: [ "main" ] + branches: [ "main", "mtls-staging" ] pull_request: - branches: [ "main" ] + branches: [ "main", "mtls-staging" ] permissions: contents: read diff --git a/README.md b/README.md index 4ffd17f..45a66ee 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Hello World Python App +# Python Hello World App ## Disclaimer @@ -7,813 +7,8 @@ > **already have full access** to the EIAP Ecosystem. > If you do not have this access, **please do not proceed.** +Python Hello World App Documentation [Here](https://developer.intelligentautomationplatform.ericsson.net/#tutorials/sample-app-in-python). + **Note:** If you need help accessing the EIAP Ecosystem, contact support at this **email address:** - -## Introduction - -This is a simple Hello World Python App with the following three endpoints: - -- **/sample-app/python/hello** is a sample endpoint. - -- **/sample-app/python/health** is an endpoint for an external agent to - monitor the App liveliness. - -- **/sample-app/python/metrics** is an endpoint that presents - the number of successful and failed invocations of - the '/sample-app/python/hello' endpoint. - -**Note:** X.509 certificates are used for authentication, and - mTLS uses them to secure communication between the App and the platform. - -## Build Docker - -Extract the downloaded sample App package. Using a command line tool, - go inside the extracted `eric-oss-hello-world-python-app-` directory. - -```bash -cd /eric-oss-hello-world-python-app- -``` - -Rename the `Dockerfile-template` file to `Dockerfile`. - -```bash -mv Dockerfile-template Dockerfile -``` - -Replace `` in the Dockerfile with a slim Python base image. -Refer to: [Python on Dockerâ„¢ Hub](https://hub.docker.com/_/python) - -Run the following command to build the image. - -```bash -docker build . -t proj-eric-oss-drop/eric-oss-hello-world-python-app: --build-arg APP_VERSION= -``` - -## Run Docker Image - -A port binding on port 8050 is done to expose the endpoints. - -```bash -docker run -p 8050:8050 --rm --name python-sample-app proj-eric-oss-drop/eric-oss-hello-world-python-app: -``` - -Run a curl request to the /sample-app/python/hello endpoint of the app. -The request should return a "Hello World!!" response. - -```bash -curl -is localhost:8050/sample-app/python/hello -``` - -Example Output: - -```http -HTTP/1.1 200 OK -Date: Thu, 17 Jun 2021 14:46:46 GMT -Content-Length: 13 -Content-Type: text/plain; charset=utf-8 - -Hello World!! -``` - -## Build the CSAR package - -For this step, install the [App Package Tool](https://developer.intelligentautomationplatform.ericsson.net/#capabilities/app-administration/tutorial-package-app). - -Once installed, the tool will be available as a Docker image -named `armdocker.rnd.ericsson.se/proj-eric-oss-dev-test/releases/eric-oss-app-package-tool:latest` - -**Note:** In the commands below, make sure to replace `` -with the correct Python Sample App version. Run the following commands -from within your project directory -`eric-oss-hello-world-python-app-`. - -```bash -mkdir -p helloworldAppPackage -``` - -The zip file includes a `csar` directory, which has the structure of the -CSAR package. - -```bash -cp -r ./csar/* ./helloworldAppPackage/ -``` - -Run the following command to generate an archive of the chart. - -```bash -helm package ./charts/eric-oss-hello-world-python-app/ -``` - -Move the created .tgz file to the OtherDefinitions/ASD directory. - -```bash -mv eric-oss-hello-world-python-app-.tgz ./helloworldAppPackage/OtherDefinitions/ASD/ -``` - -Create a folder where the CSAR App package will be stored into. - -```bash -mkdir csar-output -``` - -Generate an archive of the Docker image and store it temporarily in the `csar-output` -directory. - -```bash -docker save proj-eric-oss-drop/eric-oss-hello-world-python-app: -o csar-output/docker.tar -``` - -Run the following command locally to create a CSAR App package using the -eric-oss-app-package-tool. - -```bash -docker run --init --rm \ - --volume $PWD/csar-output/:/tmp/csar/ \ - --volume $HOME/.docker:/root/.docker \ - --volume /var/run/docker.sock:/var/run/docker.sock \ - --workdir /target \ - --volume $PWD/helloworldAppPackage:/target \ - armdocker.rnd.ericsson.se/proj-eric-oss-dev-test/releases/eric-oss-app-package-tool:latest \ - generate --tosca /target/Metadata/Tosca.meta \ - --name helloworldAppPackage \ - --images /tmp/csar/docker.tar \ - --helm3 \ - --output /tmp/csar -``` - -Run the following command to verify if the CSAR Package was created successfully. - -```bash -ls ./csar-output -``` - -`helloworldAppPackage.csar` is visible in the directory. - -## Onboard the App - -### Prerequisites for Onboarding - -Contact the platform administrator to request the following: - -- A Client certificate, Client key and platform CA certificate, - needed for secure communication with the platform APIs. -- Client ID to access the platform with the required roles, needed for authorized -communication with the platform APIs used to *onboard and instantiate* the -Hello World App. Include the required roles listed below in the request. - -| Role | Role Description | -| --------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| AppMgr_Application_Administrator | Administrator access to App Administration onboarding and instantiating Apps. | -| AppMgr_Application_Operator | Operator access to App Administration onboarding and instantiating Apps. | -| Exposure_Application_Administrator | Access to Service Exposure Onboarding APIs for the Apps. | -| UserAdministration_ExtAppRbac_Application_SecurityAdministrator | Access to Service Exposure Access control APIs for the Apps. | - -See [Client Access to REST APIs](https://developer.intelligentautomationplatform.ericsson.net/#tutorials/client-access) - for further details on client authentication. - -**Note:** Replace `` with the valid `R1 host` provided by platform administrator. - -Use the following command to generate a valid access token: - -```bash -curl --cert --key --cacert --request POST \ -https:///auth/realms/master/protocol/openid-connect/token \ ---header 'content-type: application/x-www-form-urlencoded' \ ---data "grant_type=client_credentials&client_id=" -``` - -This command returns an access token, which is used in the commands in the -following steps. See the following example of a response containing the -access token: - -```bash - "access_token": "eyJhbGciOiJSUze168rQBwD4....", - "expires_in": 300, - "refresh_expires_in": 0, - "token_type": "Bearer", - "not-before-policy": 0, - "scope": "profile" -``` - -### Steps for Onboarding - -Onboard the **Hello World CSAR App Package** using [App Administration](https://developer.intelligentautomationplatform.ericsson.net/#capabilities/app-administration/developer-guide-manage?chapter=onboard). - -Run the following command. - -```bash -curl --cert --key --cacert --location --request POST 'https:///app-onboarding/v2/app-packages' \ ---header 'Authorization: Bearer ' \ ---header 'accept: application/json' \ ---form 'file=@"/helloworldAppPackage.csar"' -``` - -Example of command result: - -```json -{ - "fileName": "helloworldAppPackage.csar", - "onboardingJob": { - "id": "af036040-a732-4af9-b65a-8103da56c35c", - "href": "/onboarding-jobs/af036040-a732-4af9-b65a-8103da56c35c" - } -} -``` - -An onboarding-job `id` is shown in the command result -(af036040-a732-4af9-b65a-8103da56c35c in the example). -This is the `JOB_ID`. Use the `JOB_ID` to get the -status of the onboarding process in the following commands: - -```bash -curl --cert --key --cacert --location --request GET 'https:///app-onboarding/v2/onboarding-jobs/' \ ---header 'Authorization: Bearer ' \ ---header 'accept: application/json' -``` - -It can take several minutes for the status to change to `ONBOARDED`. -Repeat the command until the status is changed to `ONBOARDED`. - -Example of command result: - -```json -{ - "id": "af036040-a732-4af9-b65a-8103da56c35c", - "fileName": "helloworldAppPackage.csar", - "packageVersion": "4.0.0-0", - "packageSize": "51.7659MiB", - "vendor": "Ericsson", - "type": "rApp", - "onboardStartedAt": "2025-05-31T13:51:56.616Z", - "status": "ONBOARDED", - "onboardEndedAt": "2025-05-31T13:51:59.955Z", - "events": [ - { - "type": "INFO", - "title": "Stored 1 out of 4 artifacts", - "detail": "Uploaded eric-oss-hello-world-python-appASD.yaml", - "occurredAt": "2025-05-31T13:51:58.042Z" - }, - { - "type": "INFO", - "title": "Stored 2 out of 4 artifacts", - "detail": "Uploaded eric-oss-hello-world-python-app", - "occurredAt": "2025-05-31T13:51:58.043Z" - }, - { - "type": "INFO", - "title": "Stored 3 out of 4 artifacts", - "detail": "Uploaded docker.tar", - "occurredAt": "2025-05-31T13:51:59.792Z" - }, - { - "type": "INFO", - "title": "Stored 4 out of 4 artifacts", - "detail": "Uploaded security-metadata.json", - "occurredAt": "2025-05-31T13:51:59.812Z" - } - ], - "self": { - "href": "/onboarding-jobs/af036040-a732-4af9-b65a-8103da56c35c" - }, - "app": { - "id": "rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0", - "href": "app-lifecycle-management/v3/apps/rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0" - } -} -``` - -The `APP_ID` is the `id` of the `app` returned in the previous -command (rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0 in the example). -Run the following command to initialize the App. - -```bash -curl --cert --key --cacert --location --request POST 'https:///app-lifecycle-management/v3/apps//initialization-actions' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Bearer ' \ --d '{"action": "INITIALIZE"}' -``` - -Example of command result: - -```json -{ - "app": { - "status": "INITIALIZING", - "id": "rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0", - "href": "/apps/rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0" - } -} -``` - -Repeat the following command until the status is changed to `INITIALIZED`. - -```shell -curl --cert --key --cacert --location --request GET 'https:///app-lifecycle-management/v3/apps/' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Bearer ' -``` - -Example of command result: - -```json -{ - "id": "rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0", - "type": "rApp", - "provider": "Ericsson", - "name": "eric-oss-hello-world-python-app", - "version": "4.0.0-0", - "mode": "DISABLED", - "status": "INITIALIZED", - "createdAt": "2025-05-31T13:51:59.931Z", - "components": [ - { - "type": "ASD", - "name": "eric-oss-hello-world-python-app", - "version": "4.0.0-0", - "artifacts": [ - { - "name": "docker.tar", - "type": "IMAGE" - }, - { - "name": "eric-oss-hello-world-python-appASD.yaml", - "type": "OPAQUE" - }, - { - "name": "eric-oss-hello-world-python-app", - "type": "HELM" - } - ] - }, - { - "type": "SECURITYMANAGEMENT", - "name": "security-mgmt", - "version": "1.0.0", - "artifacts": [ - { - "name": "security-metadata.json", - "type": "OPAQUE" - } - ] - } - ], - "permissions": [ - { - "resource": "kafka", - "scope": "GLOBAL" - } - ], - "roles": [], - "events": [ - { - "type": "INITIALIZE", - "title": "SUCCEEDED", - "detail": "INITIALIZE has successfully completed", - "createdAt": "2025-05-31T13:55:50.421Z" - }, - { - "type": "INITIALIZE", - "title": "STARTED", - "detail": "INITIALIZE has started", - "createdAt": "2025-05-31T13:55:34.171Z" - }, - { - "type": "CREATE", - "title": "SUCCEEDED", - "detail": "CREATE has successfully completed", - "createdAt": "2025-05-31T13:51:59.945Z" - } - ], - "self": { - "href": "/apps/rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0" - } -} -``` - -Run the following command to switch the App mode from 'DISABLED' to 'ENABLED'. - -```bash -curl --cert --key --cacert --location --request PUT 'https:///app-lifecycle-management/v3/apps//mode' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Bearer ' \ --d '{"mode": "ENABLED"}' -``` - -Example of command result: - -```json -{ - "mode": "ENABLED", - "app": { - "id": "rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0", - "href": "/apps/rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0" - } -} -``` - -## Instantiate the App - -This section describes how the App can communicate with IAM and produce logs to - the platform. The App is instantiated using App Administration and the API is - exposed and secured by the Service Exposure capability. - -### Prerequisites for Instantiation - -- You need the access token generated in **Onboard the App** prerequisite to - access the App Manager for instantiating the Hello World CSAR App Package. -- Contact your platform administrator to generate the required App key, - certificates key, certificates, and the secrets which store them. The - details of the secrets, keys, certs and EIC endpoint details will be passed - to App Administration through the `userDefinedHelmParameters` when - instantiating the App. Refer to - [App Certificate Provisioning Developer Guide](https://developer.intelligentautomationplatform.ericsson.net/#capabilities/app-cert-provisioning/developer-guide) - to understand how certificates are loaded into the App during - instantiation for secure communication. The required parameters are: - - - The `iamBaseUrl` must point to the `R1 host`, as the `/sample-app/python/hello` - endpoint in this sample app first communicates with IAM to obtain a - client token (login) before returning the "Hello World!!" string response. - - The`appSecretName`, `appKeyFileName`, `appCertFileName`, - `platformCaCertSecretName` and `platformCaCertFileName` to enable - secure communication between the App and the platform. - - The `logEndpoint` which facilitates streaming App logs to platform, - supports only mTLS communication. For more information on the variable - values required, see [App Logging Developer Guide to Produce logs](https://developer.intelligentautomationplatform.ericsson.net/#capabilities/app-logging/how-to-produce-logs?chapter=identify-environment-and-secret-variables-names). - -### Steps for Instantiation - -Use the App Administration capability to instantiate the - **Hello World CSAR App**. For more details on instantiating an App, see - [App Administration](https://developer.intelligentautomationplatform.ericsson.net/#capabilities/app-administration/developer-guide-manage?chapter=instantiate). -Run the following commands to start the instantiation process using the - `APP_ID` from **Onboard the App**. - -#### Create App Instance - -```shell -curl --cert --key --cacert --location --request POST 'https:///app-lifecycle-management/v3/app-instances' \ ---header 'accept: application/json' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Bearer ' \ --d '{ - "appId": "" -}' -``` - -Example command result: - -```json -{ - "id": "rapp-ericsson-eric-oss-hello-world-python-app-68129972", - "appId": "rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0", - "status": "UNDEPLOYED", - "credentials": { - "clientId": "rapp-ericsson-eric-oss-hello-world-python-app-68129972" - }, - "componentInstances": [ - { - "name": "eric-oss-hello-world-python-app", - "version": "4.0.0-0", - "type": "ASD", - "deployState": "UNDEPLOYED", - "properties": { - "userDefinedHelmParameters": {}, - "namespace": "", - "timeout": 5 - } - }, - { - "name": "security-mgmt", - "version": "1.0.0", - "type": "SECURITYMANAGEMENT", - "properties": { - "authenticatorType": "client-x509" - } - } - ], - "self": { - "href": "/app-instances/rapp-ericsson-eric-oss-hello-world-python-app-68129972" - }, - "app": { - "href": "/apps/rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0" - } -} -``` - -An app-instance `id` is shown in the command result - (rapp-ericsson-eric-oss-hello-world-python-app-68129972 in the example). This - is the `APP_INSTANCE_ID` used in the following commands. - -#### Deploy App Instance - -> All `userDefinedHelmParameters` are required for successful instantiation - of your App. - -```shell -curl --cert --key --cacert --location --request POST 'https:///app-lifecycle-management/v3/app-instances//deployment-actions' \ - --header 'accept: application/json' \ - --header 'Content-Type: application/json' \ - --header 'Authorization: Bearer ' \ - -d '{ - "type": "DEPLOY", - "additionalData": { - "componentInstances": [ - { - "name": "eric-oss-hello-world-python-app", - "properties": { - "timeout": 5, - "userDefinedHelmParameters": { - "iamBaseUrl": "https://", - "logEndpoint": "", - "platformCaCertSecretName": "", - "appSecretName": "", - "platformCaCertFileName": "", - "appKeyFileName": "", - "appCertFileName": "", - } - } - } - ] - } -}' -``` - -See the following example command result: - -```json -{ - "type": "DEPLOY", - "additionalData": { - "componentInstances": [ - { - "name": "eric-oss-hello-world-python-app", - "properties": { - "timeout": 5, - "userDefinedHelmParameters": { - "platformCaCertSecretName": "", - "platformCaCertFileName": "", - "iamBaseUrl": "https://", - "appSecretName": "", - "logEndpoint": "", - "appKeyFileName": "", - "appCertFileName": "", - } - } - } - ] - }, - "appInstance": { - "status": "DEPLOYING", - "href": "/app-instances/rapp-ericsson-eric-oss-hello-world-python-app-68129972" - } -} -``` - -Use the App instance ID in the following command to check the instantiation - status. Repeat the command until the health status is changed - to `"status":"DEPLOYED"`. - -```shell -curl --cert --key --cacert --location --request GET 'https:///app-lifecycle-management/v3/app-instances/' \ ---header 'accept: application/json' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Bearer ' -``` - -```json -{ - "id": "rapp-ericsson-eric-oss-hello-world-python-app-68129972", - "appId": "rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0", - "status": "DEPLOYED", - "createdAt": "2025-05-31T14:01:01.741Z", - "updatedAt": "2025-05-31T14:04:16.300Z", - "credentials": { - "clientId": "rapp-ericsson-eric-oss-hello-world-python-app-68129972" - }, - "componentInstances": [ - { - "name": "eric-oss-hello-world-python-app", - "version": "4.0.0-0", - "type": "ASD", - "deployState": "DEPLOYED", - "properties": { - "userDefinedHelmParameters": { - "iamBaseUrl": "https://", - "logEndpoint": "", - "platformCaCertSecretName": "", - "appSecretName": "", - "platformCaCertFileName": "", - "appKeyFileName": "", - "appCertFileName": "", - }, - "namespace": "", - "timeout": 5 - } - }, - { - "name": "security-mgmt", - "version": "1.0.0", - "type": "SECURITYMANAGEMENT", - "properties": { - "authenticatorType": "client-x509" - } - } - ], - "events": [ - { - "type": "DEPLOY", - "title": "SUCCEEDED", - "detail": "DEPLOY has successfully completed", - "createdAt": "2025-05-31T14:04:16.297Z" - }, - { - "type": "DEPLOY", - "title": "STARTED", - "detail": "DEPLOY has started", - "createdAt": "2025-05-31T14:04:15.609Z" - }, - { - "type": "CREATE", - "title": "SUCCEEDED", - "detail": "CREATE has successfully completed", - "createdAt": "2025-05-31T14:01:01.753Z" - } - ], - "self": { - "href": "/app-instances/rapp-ericsson-eric-oss-hello-world-python-app-68129972" - }, - "app": { - "href": "/apps/rapp-ericsson-eric-oss-hello-world-python-app-4-0-0-0" - } -} -``` - -To view your logs, access EIC and open your log viewer. -Within the log viewer, you can filter for App Logging and view the results. - -#### Onboard the Hello World Python App APIs - -Use Service Exposure to expose the Hello World App API. -For details, see [Service Exposure - Developer Guide](https://developer.intelligentautomationplatform.ericsson.net/#capabilities/service-exposure/api-exposure-developer-guide). - -To create an API to be onboarded, run the following commands: - -```bash -curl --cert --key --cacert --location --request POST 'https:///hub/apiprovisioning/v1/admin/v3/apis' \ ---header 'Authorization: Bearer ' \ ---header 'Content-Type: application/json' \ ---data '{ - "serviceCapabilityId": "hello-world-python-route-001", - "status": "active", - "apiPrefix": "/app/ericsson-helloWorldPythonApp", - "apiName": "hello-world-python-route", - "apiVersion": "v1", - "apiCategory": "/APIGM/category/api", - "apiDefinition": [ - { - "operationName": "/sample-app/python/hello/GET", - "urlPattern": "/sample-app/python/hello", - "methods": [ - "GET" - ] - } - ] -}' -``` - -To create an endpoint for the previously generated API, run the -following command: - -```bash -curl --cert --key --cacert --location --request POST 'https:///hub/apiprovisioning/v1/admin/v3/apis/hello-world-python-route-001/endpoints' \ ---header 'Authorization: Bearer ' \ ---header 'Content-Type: application/json' \ ---data '{ - "endpointId": "python-hello-001", - "serverUrl": "http://eric-oss-hello-world-python-app:8050" -}' -``` - -To bind the plugin for authorization of the previously -generated API, run the following command: - -```bash -curl --cert --key --cacert --location --request PUT 'https:///hub/apiprovisioning/v1/admin/v3/apis/hello-world-python-route-001/phases/auth/plugin-list' \ ---header 'Authorization: Bearer ' \ ---header 'Content-Type: application/json' \ ---data '[ - { - "name": "requestPartyTokenInterceptor" - } -]' -``` - -To configure the binded plugin for authorization, -run the following command: - -```bash -curl --cert --key --cacert --location --request PUT 'https:///hub/apiprovisioning/v1/admin/v3/apis/hello-world-python-route-001/plugins/requestPartyTokenInterceptor/configuration' \ ---header 'Authorization: Bearer ' \ ---header 'Content-Type: application/json' \ ---data '{ - "configurationSchemaVersion": "v0", - "configuration": { - "defaultResourceServer": "eo" - } -}' -``` - -#### Manage access control for the Hello World Python App APIs - -To allow access to the API endpoints provided by the 'Hello World' App, -Role-Based Access Control (RBAC) configuration is required. To add the -RBAC policy run the following curl command: - -```bash -curl --cert --key --cacert --location --request POST 'https:///idm/rolemgmt/v1/extapp/rbac' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Bearer ' \ ---data '{ - "tenant": "master", - "roles": [ - { - "name": "Python_SampleApp_Application_Administrator" - } - ], - "authorization": { - "resources": [ - { - "name": "python_sample_app_hello", - "type": "urn:eo:resources:extrapp", - "ownerManagedAccess": false, - "uris": [ - "/app/ericsson-helloWorldPythonApp/hello-world-python-route/v1/sample-app/python/hello" - ], - "scopes": [ - { - "name": "PATCH" - }, - { - "name": "DELETE" - }, - { - "name": "GET" - }, - { - "name": "POST" - }, - { - "name": "PUT" - } - ] - } - ], - "policies": [ - { - "name": "Python Sample App Hello Policy", - "type": "role", - "logic": "POSITIVE", - "decisionStrategy": "UNANIMOUS", - "config": { - "roles": "[{\"id\":\"Python_SampleApp_Application_Administrator\",\"required\":false}]" - } - }, - { - "name": "Python Sample App Hello Permission", - "type": "scope", - "logic": "POSITIVE", - "decisionStrategy": "AFFIRMATIVE", - "config": { - "resources": "[\"python_sample_app_hello\"]", - "scopes": "[\"GET\",\"PUT\",\"POST\",\"DELETE\",\"PATCH\"]", - "applyPolicies": "[\"Python Sample App Hello Policy\"]" - } - } - ], - "scopes": [ - { - "name": "GET" - }, - { - "name": "POST" - }, - { - "name": "DELETE" - }, - { - "name": "PUT" - }, - { - "name": "PATCH" - } - ] - } -}' -``` - -To access the `/sample-app/python/hello` endpoint, the new role -`Python_SampleApp_Application_Administrator` must be assigned to any -client accessing the endpoint. diff --git a/Dockerfile b/app.Dockerfile similarity index 91% rename from Dockerfile rename to app.Dockerfile index 6dca988..84d3c44 100644 --- a/Dockerfile +++ b/app.Dockerfile @@ -22,4 +22,6 @@ RUN echo "$USER_ID:!::0:::::" >>/etc/shadow USER $USER_ID -CMD ["./eric-oss-hello-world-python-app/main.py"] \ No newline at end of file +CMD ["./eric-oss-hello-world-python-app/main.py"] + + diff --git a/charts/eric-oss-hello-world-python-app/eric-product-info.yaml b/charts/eric-oss-hello-world-python-app/eric-product-info.yaml index ecd4eb7..a18d153 100644 --- a/charts/eric-oss-hello-world-python-app/eric-product-info.yaml +++ b/charts/eric-oss-hello-world-python-app/eric-product-info.yaml @@ -8,3 +8,10 @@ images: repoPath: "REPO_PATH" name: "eric-oss-hello-world-python-app" tag: "VERSION" + eric-oss-hello-world-python-app-envoy: + productName: "Envoy for Python Hello World App" + productNumber: "" + registry: "armdocker.rnd.ericsson.se" + repoPath: "REPO_PATH" + name: "eric-oss-hello-world-python-app-envoy" + tag: "VERSION" diff --git a/charts/eric-oss-hello-world-python-app/templates/configmap/envoy-configmap.yaml b/charts/eric-oss-hello-world-python-app/templates/configmap/envoy-configmap.yaml new file mode 100644 index 0000000..ead96c9 --- /dev/null +++ b/charts/eric-oss-hello-world-python-app/templates/configmap/envoy-configmap.yaml @@ -0,0 +1,97 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "eric-oss-hello-world-python-app.name" . }}-envoy-configmap + labels: + {{- include "eric-oss-hello-world-python-app.labels" . | indent 4 }} + {{- if .Values.labels }} + {{ .Values.labels | toYaml | indent 4 }} + {{- end }} + annotations: + {{- include "eric-oss-hello-world-python-app.product-info" . | indent 4 }} +data: + ENVOY_CONFIG_FILE: |- + static_resources: + listeners: + # TLS listener for mTLS endpoint + - name: listener_https + address: + socket_address: + address: 0.0.0.0 + port_value: 8443 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: ingress_http_secure + route_config: + virtual_hosts: + - name: secure_service + domains: ["*"] + routes: + - match: + path: "/sample-app/python/hello" + route: + cluster: eric-oss-hello-world-python-app-cluster + http_filters: + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + transport_socket: + name: envoy.transport_sockets.tls + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext + require_client_certificate: true + common_tls_context: + tls_certificates: + - certificate_chain: + filename: {{ printf "%s/%s" (default $.Values.instantiationDefaults.proxyAppCertMountPath $.Values.proxyAppCertMountPath) (default $.Values.instantiationDefaults.appCertFileName $.Values.appCertFileName) | quote }} + private_key: + filename: {{ printf "%s/%s" (default $.Values.instantiationDefaults.proxyAppCertMountPath $.Values.proxyAppCertMountPath) (default $.Values.instantiationDefaults.appKeyFileName $.Values.appKeyFileName) | quote }} + validation_context: + trusted_ca: + filename: {{ printf "%s/%s" (default $.Values.instantiationDefaults.proxyCaCertMountPath $.Values.proxyCaCertMountPath) (default $.Values.instantiationDefaults.platformCaCertFileName $.Values.platformCaCertFileName) | quote }} + # Plain HTTP listener for other endpoints + - name: listener_http + address: + socket_address: + address: 0.0.0.0 + port_value: 8080 + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: ingress_http_plain + route_config: + virtual_hosts: + - name: plain_service + domains: ["*"] + routes: + - match: + path: "/sample-app/python/health" + route: + cluster: eric-oss-hello-world-python-app-cluster + - match: + path: "/sample-app/python/metrics" + route: + cluster: eric-oss-hello-world-python-app-cluster + http_filters: + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + + clusters: + - name: eric-oss-hello-world-python-app-cluster + type: STATIC + load_assignment: + cluster_name: eric-oss-hello-world-python-app-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: 127.0.0.1 + port_value: 8050 diff --git a/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml b/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml index 4aaea3c..dd38d91 100644 --- a/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml @@ -55,6 +55,12 @@ spec: items: - key: LOG_CTRL_FILE path: logcontrol.json + - name: envoy-config + configMap: + name: {{ include "eric-oss-hello-world-python-app.name" . }}-envoy-configmap + items: + - key: ENVOY_CONFIG_FILE + path: envoy.yaml - name: platform-cacerts secret: secretName: {{ index .Values "platformCaCertSecretName" | quote }} @@ -67,12 +73,20 @@ spec: secret: secretName: {{ include "eric-oss-hello-world-python-app.clientSecret" . | quote }} defaultMode: 420 + - name: proxy-platform-cacerts + secret: + secretName: {{ index .Values "platformCaCertSecretName" | quote }} + defaultMode: 420 + - name: proxy-app-certs + secret: + secretName: {{ index .Values "appSecretName" | quote }} + defaultMode: 420 containers: - name: eric-oss-hello-world-python-app image: {{ template "eric-oss-hello-world-python-app.imagePath" (dict "imageId" "eric-oss-hello-world-python-app" "values" .Values "files" .Files) }} imagePullPolicy: {{ include "eric-oss-hello-world-python-app.registryImagePullPolicy" . | quote }} securityContext: - {{- if semverCompare ">=1.30.0" .Capabilities.KubeVersion.GitVersion }} + {{- if semverCompare ">=1.30.0" .Capabilities.KubeVersion.GitVersion }} appArmorProfile: type: {{ include "eric-oss-hello-world-python-app.appArmorProfile.type" . | default "RuntimeDefault" }} {{- end }} @@ -182,6 +196,74 @@ spec: {{- end }} resources: {{- toYaml .Values.resources.helloWorld | nindent 12 }} + - name: envoy-proxy + image: {{ template "eric-oss-hello-world-python-app.imagePath" (dict "imageId" "eric-oss-hello-world-python-app-envoy" "values" .Values "files" .Files) }} + imagePullPolicy: {{ include "eric-oss-hello-world-python-app.registryImagePullPolicy" . | quote }} + securityContext: + {{- if semverCompare ">=1.30.0" .Capabilities.KubeVersion.GitVersion }} + appArmorProfile: + type: {{ include "eric-oss-hello-world-python-app.appArmorProfile.type" . | default "RuntimeDefault" }} + {{- end }} + runAsUser: 60577 + runAsGroup: 60577 + fsGroup: 60577 + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: true + capabilities: + drop: + - all + {{- include "eric-oss-hello-world-python-app.seccomp-profile" . | indent 12 }} + command: ["envoy"] + args: ["-c", "/etc/envoy/envoy.yaml", "--base-id", "1"] + ports: + - name: envoy-http + containerPort: 8080 + protocol: TCP + - name: envoy-https + containerPort: 8443 + protocol: TCP + livenessProbe: + tcpSocket: + port: 8443 + {{- if (index .Values "probes" "proxy" "livenessProbe" "initialDelaySeconds") }} + {{ print "initialDelaySeconds: " (index .Values "probes" "proxy" "livenessProbe" "initialDelaySeconds") }} + {{- end }} + {{- if (index .Values "probes" "proxy" "livenessProbe" "failureThreshold") }} + {{ print "failureThreshold: " (index .Values "probes" "proxy" "livenessProbe" "failureThreshold") }} + {{- end }} + {{- if (index .Values "probes" "proxy" "livenessProbe" "periodSeconds") }} + {{ print "periodSeconds: " (index .Values "probes" "proxy" "livenessProbe" "periodSeconds") }} + {{- end }} + {{- if (index .Values "probes" "proxy" "livenessProbe" "timeoutSeconds") }} + {{ print "timeoutSeconds: " (index .Values "probes" "proxy" "livenessProbe" "timeoutSeconds") }} + {{- end }} + readinessProbe: + tcpSocket: + port: 8443 + {{- if (index .Values "probes" "proxy" "readinessProbe" "initialDelaySeconds") }} + {{ print "initialDelaySeconds: " (index .Values "probes" "proxy" "readinessProbe" "initialDelaySeconds") }} + {{- end }} + {{- if (index .Values "probes" "proxy" "readinessProbe" "failureThreshold") }} + {{ print "failureThreshold: " (index .Values "probes" "proxy" "readinessProbe" "failureThreshold") }} + {{- end }} + {{- if (index .Values "probes" "proxy" "readinessProbe" "periodSeconds") }} + {{ print "periodSeconds: " (index .Values "probes" "proxy" "readinessProbe" "periodSeconds") }} + {{- end }} + {{- if (index .Values "probes" "proxy" "readinessProbe" "timeoutSeconds") }} + {{ print "timeoutSeconds: " (index .Values "probes" "proxy" "readinessProbe" "timeoutSeconds") }} + {{- end }} + volumeMounts: + - name: envoy-config + mountPath: /etc/envoy + readOnly: true + - name: proxy-platform-cacerts + mountPath: {{ index .Values "proxyCaCertMountPath" | default .Values.instantiationDefaults.proxyCaCertMountPath | quote }} + readOnly: true + - name: proxy-app-certs + mountPath: {{ index .Values "proxyAppCertMountPath" | default .Values.instantiationDefaults.proxyAppCertMountPath | quote }} + readOnly: true {{- if include "eric-oss-hello-world-python-app.pullSecrets" . }} imagePullSecrets: - name: {{ template "eric-oss-hello-world-python-app.pullSecrets" . }} diff --git a/charts/eric-oss-hello-world-python-app/templates/ingress/ingress.yaml b/charts/eric-oss-hello-world-python-app/templates/ingress/ingress.yaml deleted file mode 100644 index ca297c9..0000000 --- a/charts/eric-oss-hello-world-python-app/templates/ingress/ingress.yaml +++ /dev/null @@ -1,43 +0,0 @@ -{{- if .Values.ingress.enabled -}} -{{- $fullName := include "eric-oss-hello-world-python-app.name" . -}} -{{- $servicePort := .Values.service.port -}} ---- -apiVersion: networking.k8s.io/v1beta1 -kind: Ingress -metadata: - name: {{ $fullName }} - labels: - {{- include "eric-oss-hello-world-python-app.labels" . | indent 4 }} - {{- if .Values.labels }} - {{ .Values.labels | toYaml | indent 4 }} - {{- end }} - {{- with .Values.ingress }} - annotations: - {{- include "eric-oss-hello-world-python-app.product-info" . | indent 4 }} - {{- if .annotations }} - {{ .annotations | toYaml | indent 4 }} - {{- end }} - {{- if .ingressClass }} - kubernetes.io/ingress.class: {{.ingressClass }} - {{- end -}} - {{- end }} -spec: -{{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} -{{- end }} - rules: - - host: {{ .Values.ingress.host }} - http: - paths: - - path: / - backend: - serviceName: {{ $fullName }} - servicePort: {{ $servicePort }} -{{- end }} diff --git a/charts/eric-oss-hello-world-python-app/templates/service/service.yaml b/charts/eric-oss-hello-world-python-app/templates/service/service.yaml index d90cef5..b1f5b80 100644 --- a/charts/eric-oss-hello-world-python-app/templates/service/service.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/service/service.yaml @@ -3,22 +3,26 @@ kind: Service metadata: name: {{ include "eric-oss-hello-world-python-app.name" . }} labels: - {{- include "eric-oss-hello-world-python-app.labels" . | indent 4 }} + {{- include "eric-oss-hello-world-python-app.labels" . | nindent 4 }} {{- if .Values.labels }} - {{ .Values.labels | toYaml | indent 4 }} + {{- toYaml .Values.labels | nindent 4 }} {{- end }} annotations: -{{- include "eric-oss-hello-world-python-app.product-info" . | indent 4 }} + {{- include "eric-oss-hello-world-python-app.product-info" . | nindent 4 }} spec: type: {{ .Values.service.type }} {{- if .Values.global.internalIPFamily }} ipFamilies: [{{ .Values.global.internalIPFamily }}] {{- end }} ports: - - port: {{ .Values.service.port }} - targetPort: 8050 + - port: {{ index .Values.service "http-port" }} + targetPort: {{ .Values.service.httpTargetPort | default 8080 }} protocol: TCP - name: http + name: envoy-http + - port: {{ index .Values.service "https-port" }} + targetPort: {{ .Values.service.httpsTargetPort | default 8443 }} + protocol: TCP + name: envoy-https selector: app.kubernetes.io/name: {{ include "eric-oss-hello-world-python-app.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/charts/eric-oss-hello-world-python-app/values.yaml b/charts/eric-oss-hello-world-python-app/values.yaml index e9fa74d..112f0a7 100644 --- a/charts/eric-oss-hello-world-python-app/values.yaml +++ b/charts/eric-oss-hello-world-python-app/values.yaml @@ -43,19 +43,8 @@ seccompProfile: service: type: ClusterIP - port: 8050 - -ingress: - enabled: false - ingressClass: OAM-IngressClass - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - host: "" - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local + http-port: 8080 + https-port: 8443 resources: helloWorld: @@ -108,12 +97,23 @@ probes: eric-oss-hello-world-python-app: livenessProbe: failureThreshold: 3 - initialDelaySeconds: 60 + initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 10 readinessProbe: failureThreshold: 3 - initialDelaySeconds: 60 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 10 + proxy: + livenessProbe: + failureThreshold: 3 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 10 + readinessProbe: + failureThreshold: 3 + initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 10 @@ -127,6 +127,8 @@ instantiationDefaults: platformCaCertMountPath: "/etc/tls-ca/platform/" appCertMountPath: "/etc/tls/log/" clientCredsMountPath: "/etc/client-creds/" + proxyCaCertMountPath: "/etc/certs/ca" + proxyAppCertMountPath: "/etc/certs/app" global: clientCredentials: diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..930dea8 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,21 @@ +services: + app: + build: + context: . + dockerfile: app.Dockerfile + args: + APP_VERSION: ${VERSION} + image: ${APP_IMAGE} + ports: + - "8050:8050" + + envoy: + build: + context: . + dockerfile: envoy.Dockerfile + image: ${ENVOY_IMAGE} + depends_on: + - app + ports: + - "8080:8080" + - "8443:8443" diff --git a/envoy.Dockerfile b/envoy.Dockerfile new file mode 100644 index 0000000..7d37bd4 --- /dev/null +++ b/envoy.Dockerfile @@ -0,0 +1,6 @@ +FROM envoyproxy/envoy:distroless-v1.35.0 + +USER 60577:60577 +EXPOSE 8080 8443 + +CMD ["envoy", "-c", "/etc/envoy/envoy.yaml"]