diff --git a/.gitignore b/.gitignore index 2faf43d..a557cc8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +# ---> Terraform # Local .terraform directories **/.terraform/* @@ -35,3 +36,13 @@ override.tf.json # Ignore CLI configuration files .terraformrc terraform.rc + +# ---> Ansible +*.retry + +# ---> Manually added + +# Prevents pushing secrets +*.p12 +env.ps1 +env.sh \ No newline at end of file diff --git a/README.md b/README.md index fd58839..57becee 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,48 @@ # 2024-seg360-f5xc-demo - Automation and deployment files for setting up the F5XC demo for SEG360 conference's talk #3 - Automatisation du déploiement et protection d’une application Multicloud https://www.eventbrite.ch/e/cyberseg-360-tickets-908204312547 + + Automation and deployment files for setting up the F5XC demo for SEG360 conference's talk #3 - Automatisation du déploiement et protection d’une application Multicloud + +## How to use the demo + +First. you should copy the `*.example` files, remove the `.example` extension and adapt the values. + +After this, you should be able to run: + +```powershell +cd terraform ; .\env.ps1 ; terraform apply +``` + +This takes easily 20mn to run until the end. Make sure you see the [Troubleshooting](#troubleshooting) section in case of issues. + +After this, going to [https://tde-seg.e-xpertsolutions.net/trading/login.php](https://tde-seg.e-xpertsolutions.net/trading/login.php) should show: + +![login page](assets/Screenshot%202024-07-23%20at%2016-46-49%20Arcadia%20Finance%20Login%20Page.png) + +You can login with username: `admin` and password `iloveblue`. + +After this, you should see the following dashboard: + +![dashboard](assets/Screenshot%202024-07-23%20at%2016-48-59%20Arcadia%20-%20Account%20Information.png) + +The parts circled with red triangles basically represent the 3 levels of features available. + +1. The main frontend service on AWS is available. You should be able to buy and sell actions, consistently (for example, you should get and error if you try to sell more than what you have, or you should see the figures being updated if you buy or sell). +2. The first backend service on local site with the refer-a-friend feature. You should be able to put any text in this and get a success message. If you enter twice the same you should get an error telling you so. +3. The first backend service on local site with the money-transfer feature. You should be able to consistently transfer money from your accounts to these friends (all white males (ಠ_ಠ) ). You should also be able to do this by clicking on the people faces on the lower bar. + +If services 2 and 3 cannot be reached, you will see their emplacement be replaced by "coming soon" message, showing your MCN app is not yet working. + +## Architecture + +Deployment as of v4 is represented by the following diagram: + +![diagram representing deployment as of v4](assets/SEG360-demo-v4.0-2024-07-23%2016.24.31.excalidraw.svg) + +The associated Terraform dependencies graph is represented by the following diagram: + +![diagram representing Terraform dependencies as of v4](assets/tf_dependencies_graph.svg) + +## Troubleshooting + +- On the on-premise site (Cloud B and Cloud C services), the services should already be launched (See `Distributed Apps > Virtual K8s > seg-workloads`). In case of issues with them, you can re-launch them: in the `Pods` tab, delete the running pods, they will come back freshly created. +- After `terraform apply`, the Cloud A HTTP load balancer will take time to be provisioned and propose a valid ACME challenge. Asterix DNS is very capricious so please, wait until the certificate is provisioned before making any request for `tde-seg.e-xpertsolutions.net`, otherwise it will populate Asterix's cache with bad data and you will have to wait 5mn before it gets invalidated. diff --git a/assets/SEG360-demo-v1.0-2024-07-04 15.43.02.excalidraw.svg b/assets/SEG360-demo-v1.0-2024-07-04 15.43.02.excalidraw.svg new file mode 100644 index 0000000..fa8a8aa --- /dev/null +++ b/assets/SEG360-demo-v1.0-2024-07-04 15.43.02.excalidraw.svg @@ -0,0 +1,8 @@ + + + + + + + + ClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS serviceOn-Prem ESX clusterVMWare site (CE)Backend docker serviceReverse Proxy: LB+WAF+TLS ✅L7 routing: / -> Frontend IP on AWS /api/ -> Backend IP on ESX IPsecSSL TunnelHTTPHTTPS \ No newline at end of file diff --git a/assets/SEG360-demo-v2.0-2024-07-12 17.29.49.excalidraw.svg b/assets/SEG360-demo-v2.0-2024-07-12 17.29.49.excalidraw.svg new file mode 100644 index 0000000..daea14e --- /dev/null +++ b/assets/SEG360-demo-v2.0-2024-07-12 17.29.49.excalidraw.svg @@ -0,0 +1,8 @@ + + + + + + + + ClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS serviceOn-Prem ESX clusterVMWare site (CE)Backend Docker serviceIPsecSSL TunnelHTTPHTTPSReverse proxy + LB + WAFingress trafficBackend-to-backend through HTTP LBadvertised on AWS site \ No newline at end of file diff --git a/assets/SEG360-demo-v3.0-2024-07-23 16.24.31.excalidraw.svg b/assets/SEG360-demo-v3.0-2024-07-23 16.24.31.excalidraw.svg new file mode 100644 index 0000000..bee5179 --- /dev/null +++ b/assets/SEG360-demo-v3.0-2024-07-23 16.24.31.excalidraw.svg @@ -0,0 +1,10 @@ + + + + + + + + ClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)Backend Docker services172.20.201.110IPsecSSL TunnelHTTPHTTPSF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net1ClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)Backend Docker services172.20.201.110IPsecSSL TunnelHTTPHTTPSF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net2routing inside XC network(WAF + LB + reverse proxy)ClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)Backend Docker services172.20.201.110IPsecSSL TunnelHTTPHTTPSF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net3reaching CE over securetunnelClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)Backend Docker services172.20.201.110IPsecSSL TunnelHTTPHTTPSF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net4reverse proxy to frontendserviceClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)Backend Docker services172.20.201.110IPsecSSL TunnelHTTPHTTPSF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net5back-to-back communication for refer-a-friend feature through HTTP LBadvertised on AWS siteClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)Backend Docker services172.20.201.110IPsecSSL TunnelHTTPHTTPSF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net6.1back-to-back communication for money-transfer feature through HTTP LBadvertised on AWS siteClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)Backend Docker services172.20.201.110IPsecSSL TunnelHTTPHTTPSF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net6.2back-to-back communication for money-transfer feature enhanced through publicHTTP LB advertised on internetHTTPSend user accesses the publiclyexposed HTTP LB on XC \ No newline at end of file diff --git a/assets/SEG360-demo-v4.0-2024-07-23 16.24.31.excalidraw.svg b/assets/SEG360-demo-v4.0-2024-07-23 16.24.31.excalidraw.svg new file mode 100644 index 0000000..8711426 --- /dev/null +++ b/assets/SEG360-demo-v4.0-2024-07-23 16.24.31.excalidraw.svg @@ -0,0 +1,17 @@ + + + + + + + + ClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)Containerized backend serviceOn F5XC CE App Stack (K8s cluster)IPsecSSL TunnelHTTPF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net1ClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)IPsecSSL TunnelHTTPHTTPF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net2routing inside XC network(WAF + LB + reverse proxy)ClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)IPsecSSL TunnelHTTPHTTPF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net3reaching CE over securetunnelClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)IPsecSSL TunnelHTTPHTTPF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net4reverse proxy to frontendserviceClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)IPsecSSL TunnelHTTPHTTPF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net5back-to-back communication for refer-a-friend feature through HTTP LBadvertised on AWS siteClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)IPsecSSL TunnelHTTPHTTPF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net6.1back-to-back communication for money-transfer feature through HTTP LBadvertised on AWS siteClientF5XC networkAWS VPCVPC gateway (CE)Frontend ECS service10.20.10.xOn-Prem ESX clusterVMWare site (CE)IPsecSSL TunnelHTTPHTTPF5XC RE HTTP LBtde-seg.e-xpertsolutions.netF5XC CE HTTP LBfriends.tde-seg.e-xpertsolutions.nettransfer.tde-seg.e-xpertsolutions.net6.2back-to-back communication for money-transfer feature enhanced through publicHTTP LB advertised on internetHTTPSend user accesses the publiclyexposed HTTP LB on XCHTTPContainerized backend serviceOn F5XC CE App Stack (K8s cluster)Containerized backend serviceOn F5XC CE App Stack (K8s cluster)Containerized backend serviceOn F5XC CE App Stack (K8s cluster)Containerized backend serviceOn F5XC CE App Stack (K8s cluster)Containerized backend serviceOn F5XC CE App Stack (K8s cluster)Containerized backend serviceOn F5XC CE App Stack (K8s cluster) \ No newline at end of file diff --git a/assets/Screenshot 2024-07-23 at 16-46-49 Arcadia Finance Login Page.png b/assets/Screenshot 2024-07-23 at 16-46-49 Arcadia Finance Login Page.png new file mode 100644 index 0000000..334983c Binary files /dev/null and b/assets/Screenshot 2024-07-23 at 16-46-49 Arcadia Finance Login Page.png differ diff --git a/assets/Screenshot 2024-07-23 at 16-48-59 Arcadia - Account Information.png b/assets/Screenshot 2024-07-23 at 16-48-59 Arcadia - Account Information.png new file mode 100644 index 0000000..def4342 Binary files /dev/null and b/assets/Screenshot 2024-07-23 at 16-48-59 Arcadia - Account Information.png differ diff --git a/assets/tf_dependencies_graph.svg b/assets/tf_dependencies_graph.svg new file mode 100644 index 0000000..2dafea8 --- /dev/null +++ b/assets/tf_dependencies_graph.svg @@ -0,0 +1,235 @@ + + + + + + +G + + + +data.aws_network_interface.interface_tags + +data.aws_network_interface.interface_tags + + + +aws_ecs_service.cloud_a_service + +aws_ecs_service.cloud_a_service + + + +data.aws_network_interface.interface_tags->aws_ecs_service.cloud_a_service + + + + + +data.volterra_http_loadbalancer_state.cloud_a_lb_state + +data.volterra_http_loadbalancer_state.cloud_a_lb_state + + + +volterra_http_loadbalancer.cloud_a + +volterra_http_loadbalancer.cloud_a + + + +data.volterra_http_loadbalancer_state.cloud_a_lb_state->volterra_http_loadbalancer.cloud_a + + + + + +aws_ecs_cluster.cloud_a_cluster + +aws_ecs_cluster.cloud_a_cluster + + + +aws_ecs_service.cloud_a_service->aws_ecs_cluster.cloud_a_cluster + + + + + +aws_ecs_task_definition.cloud_a_task + +aws_ecs_task_definition.cloud_a_task + + + +aws_ecs_service.cloud_a_service->aws_ecs_task_definition.cloud_a_task + + + + + +aws_security_group.allow_all + +aws_security_group.allow_all + + + +aws_ecs_service.cloud_a_service->aws_security_group.allow_all + + + + + +volterra_dns_zone.cloud_b_c_records + +volterra_dns_zone.cloud_b_c_records + + + +aws_ecs_task_definition.cloud_a_task->volterra_dns_zone.cloud_b_c_records + + + + + +volterra_tf_params_action.apply_aws_vpc + +volterra_tf_params_action.apply_aws_vpc + + + +aws_security_group.allow_all->volterra_tf_params_action.apply_aws_vpc + + + + + +volterra_app_firewall.seg_waf_config + +volterra_app_firewall.seg_waf_config + + + +volterra_aws_vpc_site.cloud_a_site + +volterra_aws_vpc_site.cloud_a_site + + + +volterra_cloud_credentials.aws_cred + +volterra_cloud_credentials.aws_cred + + + +volterra_aws_vpc_site.cloud_a_site->volterra_cloud_credentials.aws_cred + + + + + +volterra_dns_zone.cloud_b_c_records->volterra_tf_params_action.apply_aws_vpc + + + + + +volterra_healthcheck.clouds + +volterra_healthcheck.clouds + + + +volterra_http_loadbalancer.cloud_a->volterra_app_firewall.seg_waf_config + + + + + +volterra_origin_pool.cloud_a + +volterra_origin_pool.cloud_a + + + +volterra_http_loadbalancer.cloud_a->volterra_origin_pool.cloud_a + + + + + +volterra_service_policy.allow_e_xpert_wan + +volterra_service_policy.allow_e_xpert_wan + + + +volterra_http_loadbalancer.cloud_a->volterra_service_policy.allow_e_xpert_wan + + + + + +volterra_http_loadbalancer.cloud_b_c + +volterra_http_loadbalancer.cloud_b_c + + + +volterra_http_loadbalancer.cloud_b_c->volterra_app_firewall.seg_waf_config + + + + + +volterra_http_loadbalancer.cloud_b_c->volterra_aws_vpc_site.cloud_a_site + + + + + +volterra_origin_pool.cloud_b_c + +volterra_origin_pool.cloud_b_c + + + +volterra_http_loadbalancer.cloud_b_c->volterra_origin_pool.cloud_b_c + + + + + +volterra_modify_site.tde_seg_ce_vmware_gve + +volterra_modify_site.tde_seg_ce_vmware_gve + + + +volterra_origin_pool.cloud_a->data.aws_network_interface.interface_tags + + + + + +volterra_origin_pool.cloud_a->volterra_healthcheck.clouds + + + + + +volterra_origin_pool.cloud_b_c->volterra_healthcheck.clouds + + + + + +volterra_tf_params_action.apply_aws_vpc->volterra_aws_vpc_site.cloud_a_site + + + + + diff --git a/bruno/CRUD HTTP Load Balancer/Create Certificate for RE LB.bru b/bruno/CRUD HTTP Load Balancer/Create Certificate for RE LB.bru new file mode 100644 index 0000000..9536fd7 --- /dev/null +++ b/bruno/CRUD HTTP Load Balancer/Create Certificate for RE LB.bru @@ -0,0 +1,30 @@ +meta { + name: Create Certificate for RE LB + type: http + seq: 2 +} + +post { + url: {{basename}}/api/config/namespaces/{{namespace}}/certificates + body: json + auth: inherit +} + +body:json { + { + "metadata": { + "name": "seg-selfsigned-re-cert", + "description": "Certificate presented by the Regional Edge's load balancer for HTTPS", + "disable": false + }, + "spec": { + "certificate_url": "string:///LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlEVkRDQ0FqeWdBd0lCQWdJUUdVZkFmbHY1KzVaTE9RWnp5bW04aGpBTkJna3Foa2lHOXcwQkFRc0ZBREFvDQpNU1l3SkFZRFZRUUREQjF6WldjdWJHRmlieTVsTFhod1pYSjBjMjlzZFhScGIyNXpMbXhoYmpBZUZ3MHlOREEyDQpNVGN4TVRFek1UZGFGdzB6TkRBMk1UY3hNVEl6TVRkYU1DZ3hKakFrQmdOVkJBTU1IWE5sWnk1c1lXSnZMbVV0DQplSEJsY25SemIyeDFkR2x2Ym5NdWJHRnVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDDQpBUUVBM3IvSnptSkR0ZFBiM2poR2V0ZEcraUNjditBRG81aktJakVFdEUvWXJkZWx4bi82Z1huMHBwNG1XVmlKDQpoSXdQKzB5Tkp6OE5YZ2lEaWorR3E2Tk1TY2orWTJMVHlGRGlERWw0SytuMFdBL2N2N0ZYcXowaS9rMnFzSW1xDQpSY1RjVFQraEVjNDFiM3hJZUFONi93RXBHYmhBcjFEbEZIQzQ0TG1DNXM4MlFpajQyaWVCYlRZOEhzM2lEOUdUDQpaM09yejl1dE5PV3hDckZhR2h3Rm9JSmdCWkFWeTV1Umd3R3YyRjlGVjJkNUQwRjVjYlZuZzhTRGpwWnYzT0QrDQpIZHZ5Sjh2QkRScDlLYTFOTjFxUkhMZDFMM3lhZndpL1gyK240c3V0S1ZJRzEvSXU1T0EyOUpQdEVQRWpvRkxjDQpOT1lieG9PWlRhT1E2QTMybitpdzU0ME9hUUlEQVFBQm8zb3dlREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdIUVlEDQpWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3SUdDQ3NHQVFVRkJ3TUJNQ2dHQTFVZEVRUWhNQitDSFhObFp5NXNZV0p2DQpMbVV0ZUhCbGNuUnpiMngxZEdsdmJuTXViR0Z1TUIwR0ExVWREZ1FXQkJRUlhVYnRvdVNPamMrd2c5eVhqczJ0DQpoeWs0V0RBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQXM2ajZhemE3T0RnZ0FNcGVqQ1hSY1pyaTRIZi9DZkRYDQpiZkwxRVZ1Yy9BVnF3bFhUNk1yd0lOWGh1bTA2cDVjb0I1Ym9yb2pIdmxKd0w3YXVJS3FSN1h1NnRoaVNYcllhDQpPK04yYVpraFpzakpGa0ZMc2dLdXNabmU1bDF5b21uZmUzRUNXYXpuWVpuZkxZYWRZdWdjVjg3V0VReEs1VEFrDQozRmh1SFRMdVZQSFFWTmlyancrQ2xJU1p4OHZFOXZwMzEvSmhHNTlCdTdwcDQvQ3dIaklLQmoyMkhkbTFrRWhFDQpiLzFMZlYzaWdObTZKNVB6NmFFNzdTTjY2ak9oRkZFakZZbjlyd3pCUTF4Wi9FWEJEM2c1c29IOFFUY0VoSnRFDQpnelpvRFJ3QmR2NncvUW8zZU9hUWQrNHVDUFpyYWsxeHp4VUhOQmV6OHNVOXRveG1GVFBXbVE9PQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ0K", + "private_key": { + "blindfold_secret_info": { + "location": "string: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" + } + }, + "disable_ocsp_stapling": {} + } + } +} diff --git a/bruno/CRUD HTTP Load Balancer/Create HTTP Load Balancer.bru b/bruno/CRUD HTTP Load Balancer/Create HTTP Load Balancer.bru new file mode 100644 index 0000000..3e2ea6e --- /dev/null +++ b/bruno/CRUD HTTP Load Balancer/Create HTTP Load Balancer.bru @@ -0,0 +1,106 @@ +meta { + name: Create HTTP Load Balancer + type: http + seq: 6 +} + +post { + url: {{basename}}/api/config/namespaces/{{namespace}}/http_loadbalancers + body: json + auth: inherit +} + +body:json { + { + "metadata": { + "name": "{{http_lb_name}}", + "description": "Automatically deployed load balancer for the NGINX lab application", + "disable": false + }, + "spec": { + "domains": [ + "seg.labo.e-xpertsolutions.lan" + ], + "https": { + "http_redirect": false, + "add_hsts": false, + "port": 443, + "default_header": {}, + "enable_path_normalize": {}, + "non_default_loadbalancer": {}, + "header_transformation_type": { + "legacy_header_transformation": {} + }, + "connection_idle_timeout": 120000, + "tls_cert_params": { + "tls_config": { + "default_security": {} + }, + "certificates": [ + { + "tenant": "f5-channel-rwtqhrvn", + "namespace": "expertsolutions-partner-emea", + "name": "seg-selfsigned-re-cert", + "kind": "certificate" + } + ], + "no_mtls": {} + }, + "http_protocol_options": { + "http_protocol_enable_v1_v2": {} + } + }, + "advertise_on_public_default_vip": {}, + "default_route_pools": [ + { + "pool": { + "tenant": "f5-channel-rwtqhrvn", + "namespace": "expertsolutions-partner-emea", + "name": "seg-nginx-origin-auto", + "kind": "origin_pool" + }, + "weight": 1, + "priority": 1, + "endpoint_subsets": {} + } + ], + "disable_waf": {}, + "add_location": true, + "no_challenge": {}, + "more_option": { + "request_headers_to_add": [ + { + "name": "X-Forwarded-Host", + "value": "seg.labo.e-xpertsolutions.lan", + "append": false + } + ], + "max_request_header_size": 60, + "idle_timeout": 30000, + "disable_default_error_pages": false + }, + "user_id_client_ip": {}, + "disable_rate_limit": {}, + "active_service_policies": { + "policies": [ + { + "tenant": "f5-channel-rwtqhrvn", + "namespace": "expertsolutions-partner-emea", + "name": "seg-allow-e-xpert-wan", + "kind": "service_policy" + } + ] + }, + "round_robin": {}, + "disable_trust_client_ip_headers": {}, + "disable_malicious_user_detection": {}, + "disable_api_discovery": {}, + "disable_bot_defense": {}, + "disable_api_definition": {}, + "disable_ip_reputation": {}, + "disable_client_side_defense": {}, + "system_default_timeouts": {}, + "l7_ddos_action_default": {} + } + } +} diff --git a/bruno/CRUD HTTP Load Balancer/Create Origin Pool.bru b/bruno/CRUD HTTP Load Balancer/Create Origin Pool.bru new file mode 100644 index 0000000..7a073b5 --- /dev/null +++ b/bruno/CRUD HTTP Load Balancer/Create Origin Pool.bru @@ -0,0 +1,60 @@ +meta { + name: Create Origin Pool + type: http + seq: 4 +} + +post { + url: {{basename}}/api/config/namespaces/{{namespace}}/origin_pools + body: json + auth: inherit +} + +body:json { + { + "metadata": { + "name": "seg-nginx-origin-auto", + "description": "Origin pool for load balanced NGINX application automatically created", + "disable": false + }, + "spec": { + "origin_servers": [ + { + "private_name": { + "dns_name": "tdenginxce.labo.e-xpertsolutions.lan", + "refresh_interval": 300, + "site_locator": { + "site": { + "tenant": "f5-channel-rwtqhrvn", + "namespace": "system", + "name": "tdef5xcsite", + "kind": "site" + } + }, + "outside_network": {} + } + } + ], + "use_tls": { + "use_host_header_as_sni": {}, + "tls_config": { + "default_security": {} + }, + "use_server_verification": { + "trusted_ca": { + "tenant": "f5-channel-rwtqhrvn", + "namespace": "expertsolutions-partner-emea", + "name": "seg-nginx-appcert-auto", + "kind": "trusted_ca_list" + } + }, + "no_mtls": {} + }, + "port": 443, + "same_as_endpoint_port": {}, + "healthcheck": [], + "loadbalancer_algorithm": "LB_OVERRIDE", + "endpoint_selection": "LOCAL_PREFERRED" + } + } +} diff --git a/bruno/CRUD HTTP Load Balancer/Create Root CA Certificate for NGINX cert validation.bru b/bruno/CRUD HTTP Load Balancer/Create Root CA Certificate for NGINX cert validation.bru new file mode 100644 index 0000000..e49c4f3 --- /dev/null +++ b/bruno/CRUD HTTP Load Balancer/Create Root CA Certificate for NGINX cert validation.bru @@ -0,0 +1,24 @@ +meta { + name: Create Root CA Certificate for NGINX cert validation + type: http + seq: 3 +} + +post { + url: {{basename}}/api/config/namespaces/{{namespace}}/trusted_ca_lists + body: json + auth: none +} + +body:json { + { + "metadata": { + "name": "seg-nginx-appcert-auto", + "description": "Certificate served by the NGINX application to the load balancer", + "disable": false + }, + "spec": { + "trusted_ca_url": "string:///LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVJekNDQXd1Z0F3SUJBZ0lVQ1FwclNrdHE4dEl1dXZvNS9HbXM2TTRaYXdjd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dhQXhDekFKQmdOVkJBWVRBa05JTVEwd0N3WURWUVFJREFSV1lYVmtNUkV3RHdZRFZRUUhEQWhNWVhWegpZVzV1WlRFYU1CZ0dBMVVFQ2d3UlJTMTRjR1Z5ZENCVGIyeDFkR2x2Ym5NeEpqQWtCZ05WQkFNTUhYUmtaVzVuCmFXNTRMbVV0ZUhCbGNuUnpiMngxZEdsdmJuTXViR0Z1TVNzd0tRWUpLb1pJaHZjTkFRa0JGaHgwWkdWdGIyNTAKUUdVdGVIQmxjblJ6YjJ4MWRHbHZibk11WTI5dE1CNFhEVEkwTURVeE56QTRNakV5TlZvWERUSTFNRFV4TnpBNApNakV5TlZvd2dhQXhDekFKQmdOVkJBWVRBa05JTVEwd0N3WURWUVFJREFSV1lYVmtNUkV3RHdZRFZRUUhEQWhNCllYVnpZVzV1WlRFYU1CZ0dBMVVFQ2d3UlJTMTRjR1Z5ZENCVGIyeDFkR2x2Ym5NeEpqQWtCZ05WQkFNTUhYUmsKWlc1bmFXNTRMbVV0ZUhCbGNuUnpiMngxZEdsdmJuTXViR0Z1TVNzd0tRWUpLb1pJaHZjTkFRa0JGaHgwWkdWdApiMjUwUUdVdGVIQmxjblJ6YjJ4MWRHbHZibk11WTI5dE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBCk1JSUJDZ0tDQVFFQTJYQTVCOXZ2MFltU2ZUUit1VzJIM2VNelVxMTVqSjZ4K25mZVZKNUJnYU56Q1huNHZ0S0sKazZDMDBucUpqdDFXaWVuaDBTQ0JMcUJMbDZMS2RMemhhQm9zU0RTaHVOMkRlUy9CR2pEQ21Ba2NiTjJ0aldIVApzbUxNL3pOYlhDSUd3NFFzVWsxbUNaV3lPeFFwVUtIeDBWL1lBSERWa09CTXg0UVFKWE9zM1BzaGh4VkZsWWYzCit6MjludnpPVVdCSEZDVlphZjJzSWJjVnkzL1hlWnBoem1IRE1IMkx3NjRGSDZYRTJXVHlVVnNzczlpUDdBWUQKM1V2VmFJUWlXNzdHTmprUmRnVUhsaUJIQjJYMUNjU3hLOG44am5UK09CL3UyV0FYbHYwM042Q2VlUHdVMnQ0ZwpaMzY2clU0UXkvNmJHZUg2R1ZhWDJ2YjJvbU0raklmL3Z3SURBUUFCbzFNd1VUQWRCZ05WSFE0RUZnUVU5SGZkCmNEVktXUjVkb0FlUjdHeTZMT2JORUZvd0h3WURWUjBqQkJnd0ZvQVU5SGZkY0RWS1dSNWRvQWVSN0d5NkxPYk4KRUZvd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWovZm1PM0JZQjVVNwpWb2V0azlxWis0Y2VCUEFpQWlwZ202Rmh4QU5ycVFSdys5aXQ4NjZhTGNQcTBUMFUrTlRqUk9ubTNuT0xSZGZGCjF3bGpEWTVvOVdQSEFIWHVxVDJJazhmSVdFTTF0Z1FpL2EzajF5YTFuaWM0VXorNzY1VVVaemR6dHdJZ3FYa3oKdHo2Zk80N1IycXR6c2Y1WVdzaDRqWlFrTXVqRXZEUkMwajlHUkFteW5rWk9Nc09IeVE3ZEhNd3lOeTFMTXp6ZQpCYkVjYUc1cWxocVcvQTJxY05YOUYxOWNmUmxyMElldHZXZlFoQnBHNEJzL2lwVHVXUGdNTHB6UEdRT0hWOU1QCjZFK2hGQlhubW5sYkYxMmRCNHpzazMrYy9VdVR3MStYNFZ0bVZiZmJuSVFUdWk0eEJPc3BGZ1ZjdUhZbzdnRmcKRnlVSlpCemRIdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" + } + } +} diff --git a/bruno/CRUD HTTP Load Balancer/Create Service Policy Allow e-Xpert WAN.bru b/bruno/CRUD HTTP Load Balancer/Create Service Policy Allow e-Xpert WAN.bru new file mode 100644 index 0000000..cf3c7a1 --- /dev/null +++ b/bruno/CRUD HTTP Load Balancer/Create Service Policy Allow e-Xpert WAN.bru @@ -0,0 +1,36 @@ +meta { + name: Create Service Policy Allow e-Xpert WAN + type: http + seq: 5 +} + +post { + url: {{basename}}/api/config/namespaces/{{namespace}}/service_policys + body: json + auth: inherit +} + +body:json { + { + "metadata": { + "name": "seg-allow-e-xpert-wan", + "description": "Allows WAN IPs from e-Xpert owned public subnets", + "disable": false + }, + "spec": { + "any_server": {}, + "allow_list": { + "prefix_list": { + "prefixes": [ + "46.14.179.0/27", + "83.166.158.32/27", + "81.63.137.43/32" + ] + }, + "country_list": [], + "tls_fingerprint_classes": [], + "default_action_next_policy": {} + } + } + } +} diff --git a/bruno/CRUD HTTP Load Balancer/Delete HTTP Load Balancer.bru b/bruno/CRUD HTTP Load Balancer/Delete HTTP Load Balancer.bru new file mode 100644 index 0000000..df1409d --- /dev/null +++ b/bruno/CRUD HTTP Load Balancer/Delete HTTP Load Balancer.bru @@ -0,0 +1,11 @@ +meta { + name: Delete HTTP Load Balancer + type: http + seq: 8 +} + +delete { + url: {{basename}}/api/config/namespaces/{{namespace}}/http_loadbalancers/{{http_lb_name}} + body: none + auth: inherit +} diff --git a/bruno/CRUD HTTP Load Balancer/Get HTTP Load Balancer tdenginxauto.bru b/bruno/CRUD HTTP Load Balancer/Get HTTP Load Balancer tdenginxauto.bru new file mode 100644 index 0000000..719600f --- /dev/null +++ b/bruno/CRUD HTTP Load Balancer/Get HTTP Load Balancer tdenginxauto.bru @@ -0,0 +1,11 @@ +meta { + name: Get HTTP Load Balancer tdenginxauto + type: http + seq: 7 +} + +get { + url: {{basename}}/api/config/namespaces/{{namespace}}/http_loadbalancers/{{http_lb_name}} + body: none + auth: inherit +} diff --git a/bruno/CRUD HTTP Load Balancer/List Configure HTTP Load Balancer.bru b/bruno/CRUD HTTP Load Balancer/List Configure HTTP Load Balancer.bru new file mode 100644 index 0000000..767cd80 --- /dev/null +++ b/bruno/CRUD HTTP Load Balancer/List Configure HTTP Load Balancer.bru @@ -0,0 +1,22 @@ +meta { + name: List Configure HTTP Load Balancer + type: http + seq: 1 +} + +get { + url: {{basename}}/api/config/namespaces/{{namespace}}/http_loadbalancers + body: none + auth: inherit +} + +headers { + accept: application/json + Access-Control-Allow-Origin: * + x-volterra-apigw-tenant: null +} + +assert { + res.status: eq 200 + res.body.items[1].name: eq tde-nginx-lab +} diff --git a/bruno/CRUD Sites/Get AWS-VPC-Site seg-aws-site.bru b/bruno/CRUD Sites/Get AWS-VPC-Site seg-aws-site.bru new file mode 100644 index 0000000..4f9c770 --- /dev/null +++ b/bruno/CRUD Sites/Get AWS-VPC-Site seg-aws-site.bru @@ -0,0 +1,22 @@ +meta { + name: Get AWS-VPC-Site seg-aws-site + type: http + seq: 3 +} + +get { + url: {{basename}}/api/config/namespaces/system/aws_vpc_sites/seg-aws-site + body: none + auth: inherit +} + +vars:post-response { + workload_subnet_id: res.body.spec.cloud_site_info.subnet_ids[0].workload_subnet.id +} + +assert { + res.body.spec.site_state: neq FAILED + res.body.spec.validation_state: eq VALIDATION_SUCCEEDED + res.body.spec.cloud_site_info.subnet_ids: length 1 + res.body.spec.cloud_site_info.subnet_ids[0].workload_subnet.id: isDefined +} diff --git a/bruno/CRUD Sites/Get Site tdef5xcsite.bru b/bruno/CRUD Sites/Get Site tdef5xcsite.bru new file mode 100644 index 0000000..f7a7755 --- /dev/null +++ b/bruno/CRUD Sites/Get Site tdef5xcsite.bru @@ -0,0 +1,11 @@ +meta { + name: Get Site tdef5xcsite + type: http + seq: 2 +} + +get { + url: {{basename}}/api/config/namespaces/system/sites/tdef5xcsite + body: none + auth: inherit +} diff --git a/bruno/CRUD Sites/Liste Sites.bru b/bruno/CRUD Sites/Liste Sites.bru new file mode 100644 index 0000000..3a0c224 --- /dev/null +++ b/bruno/CRUD Sites/Liste Sites.bru @@ -0,0 +1,11 @@ +meta { + name: Liste Sites + type: http + seq: 1 +} + +get { + url: {{basename}}/api/config/namespaces/system/sites + body: none + auth: inherit +} diff --git a/bruno/bruno.json b/bruno/bruno.json new file mode 100644 index 0000000..fdd2ee1 --- /dev/null +++ b/bruno/bruno.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "name": "seg360-demo", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ], + "presets": { + "requestType": "http", + "requestUrl": "{{basename}}" + } +} \ No newline at end of file diff --git a/bruno/collection.bru b/bruno/collection.bru new file mode 100644 index 0000000..cf09ab2 --- /dev/null +++ b/bruno/collection.bru @@ -0,0 +1,13 @@ +headers { + Access-Control-Allow-Origin: * + x-volterra-apigw-tenant: f5-channel + accept: application/json +} + +auth { + mode: bearer +} + +auth:bearer { + token: APIToken {{auth_token}} +} diff --git a/bruno/environments/seg360-demo-env.bru b/bruno/environments/seg360-demo-env.bru new file mode 100644 index 0000000..b1c3bb3 --- /dev/null +++ b/bruno/environments/seg360-demo-env.bru @@ -0,0 +1,8 @@ +vars { + namespace: expertsolutions-partner-emea + basename: https://f5-channel.console.ves.volterra.io + http_lb_name: seg-nginx-lab-auto +} +vars:secret [ + auth_token +] diff --git a/terraform/.terraform.lock.hcl b/terraform/.terraform.lock.hcl new file mode 100644 index 0000000..b5cec04 --- /dev/null +++ b/terraform/.terraform.lock.hcl @@ -0,0 +1,38 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.68.0" + constraints = "~> 5.0" + hashes = [ + "h1:J3selLplasdTyf03y+6NsPVMEP+EIXxbrWWL/k5KkeU=", + "zh:045f37b115a6c94a05c6a5f2aacfe4cecbaf4b40b56917ba852d988d487e94bf", + "zh:0c388f1a94e7941cf7e6abcd8d958a3e325e513cb60affa3cac82e75c7bbbb73", + "zh:15b1f2587c06bff35a15f2d1c22eab395d549908daf05582608d729cdf54ba40", + "zh:16a9c0c7fa7a33aa22313d4444aeecde20831bf51f9b481a0406e3cf583378fc", + "zh:3330c0d49fb329dff6de17913e1a774e75aa0913106c3197814c73c3a12a4c3f", + "zh:40920318f774ff397c7b6a01b5e89e46eb1a55d7dc9943a310669a9357b9b501", + "zh:838fbac358bb72f46c8d359a28a3effb6a9d7137cdd72b9e4d2f0fcf803dc462", + "zh:84e694c0720bf54b3b8521bf6e05700abe4a1b3e7dd2a104efd1eb55ae5866a0", + "zh:90606c399498027d7d07ab78a71b574a5d8b982c4372e6b67479f7e39e153e2f", + "zh:9162cf25d5c0fdf672c9bbc4c3c84dd87ab6a15b4971df1f32aea6b477c0e028", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9cd8ec40a88b25e9f0f7d7f51460a921f4529554a260ffbe5083ddeba2f41ae3", + "zh:adeffac1d01a35bc8d2497ccceb9978b4746872143016c2c631de6cb38b6aa8d", + "zh:c7b682c81f9ae850669deb6239a66d8aa960abed984aad25db2d3954c09c2616", + "zh:d10b9f40934e14d55cfc5731d728507e50d014561322e9e0c84b33ab255a4d51", + ] +} + +provider "registry.terraform.io/volterraedge/volterra" { + version = "0.11.37" + constraints = "0.11.37" + hashes = [ + "h1:xquwi/b13ATklZJUm+AIlVeuC+V/GTVRyl2DeRx9naE=", + "zh:367ab9cb0b04a9c92a6430f7a4dcee95331f34f4a471370450ba2fa6b548b92e", + "zh:3d3427c4460e6df4633da12cba7e582140fca139860ef8543d1adc666484fdde", + "zh:a7d54a49d1dc0145f217d3ea0639b95590d38d1dfe51db1a71b82878e6d06297", + "zh:b20d1c31a86f9f094b85a17d229ae8facfd6b02bdbd000be4ae62f66f248fca1", + "zh:db5b9117903045bb77827e2ecb0621e25f8651863cb61dc3dcc6433ed24be503", + ] +} diff --git a/terraform/aws.tf b/terraform/aws.tf new file mode 100644 index 0000000..7ba1f2d --- /dev/null +++ b/terraform/aws.tf @@ -0,0 +1,286 @@ +// F5XC's credentials for controlling AWS +resource "volterra_cloud_credentials" "aws_cred" { + name = "seg-aws-creds" + namespace = "system" + aws_secret_key { + access_key = var.aws_f5xc_access_key + secret_key { + blindfold_secret_info { + location = format("string:///%s", var.aws_f5xc_secret_key_blindfolded) + } + } + } +} + +// AWS Site's definitions +resource "volterra_aws_vpc_site" "cloud_a_site" { + name = "seg-cloud-a-site" + description = "Site deployed on AWS for testing the SEG360 demo" + namespace = "system" + aws_region = var.aws_region + block_all_services = true + direct_connect_disabled = true + disk_size = 0 + egress_gateway_default = true + instance_type = "t3.xlarge" + disable_internet_vip = true + f5xc_security_group = true + ssh_key = var.aws_ssh_key + no_worker_nodes = true + + vpc { + new_vpc { + autogenerate = true + primary_ipv4 = var.aws_vpc_cidr + } + } + + ingress_egress_gw { + aws_certified_hw = "aws-byol-multi-nic-voltmesh" + no_dc_cluster_group = true + no_forward_proxy = true + no_global_network = true + no_inside_static_routes = true + no_network_policy = true + no_outside_static_routes = true + sm_connection_public_ip = true + az_nodes { + aws_az_name = var.aws_az + reserved_inside_subnet = true + outside_subnet { + subnet_param { + ipv4 = "10.20.20.0/24" + } + } + workload_subnet { + subnet_param { + ipv4 = "10.20.10.0/24" + } + } + } + } + + aws_cred { + name = volterra_cloud_credentials.aws_cred.name + namespace = "system" + tenant = var.tenant + } + +} + +// ACTION TO PERFORM FOR SITE DEFINITION +resource "volterra_tf_params_action" "apply_aws_vpc" { + site_name = volterra_aws_vpc_site.cloud_a_site.name + site_kind = "aws_vpc_site" + action = "apply" + wait_for_action = true +} + +// DNS RECORDS FOR INTERNAL PRIVATE LOAD BALANCERS +// These need to be defined before launching the services. +// Nginx expects to resolve the domains for the templated config +resource "volterra_dns_zone" "cloud_b_c_records" { + for_each = tomap({ + cloud_b = { + name = local.cloud_b_domain + } + cloud_c = { + name = local.cloud_c_domain + } + }) + name = each.value.name + namespace = "system" + + primary { + dnssec_mode { + # the enable{} block works but triggers change detection + disable = false + } + default_rr_set_group { + ttl = "120" + a_record { + name = "" + values = [local.aws_ce_instance_private_ip] + } + } + } +} + +// DEFINES THE WEBAPP TASK AND SERVICE +resource "aws_ecs_task_definition" "cloud_a_task" { + family = "seg-cloud-a-tasks" + network_mode = "awsvpc" + requires_compatibilities = ["FARGATE"] + cpu = 256 + memory = 512 + execution_role_arn = "arn:aws:iam::699300912331:role/ecsTaskExecutionRole" + runtime_platform { + cpu_architecture = "X86_64" + operating_system_family = "LINUX" + } + + volume { + name = "MainApp" + } + volume { + name = "files" + } + container_definitions = jsonencode([ + { + name = "reverse-proxy" + image = var.aws_reverse_proxy_image + essential = true + cpu = 0 + portMappings = [{ + name = "reverse-proxy-8080-tcp" + containerPort = 8080 + hostPort = 8080 + protocol = "tcp" + appProtocol = "http" + }] + environment = [ + { + name = "CLOUD_B_DOMAIN" + value = volterra_dns_zone.cloud_b_c_records["cloud_b"].name + }, + { + name = "CLOUD_C_DOMAIN" + value = volterra_dns_zone.cloud_b_c_records["cloud_c"].name } + ] + dependsOn = [ + { + containerName = "frontend" + condition = "START" + }, { + containerName = "backend" + condition = "START" + } + ] + }, + { + name = "frontend" + image = var.aws_frontend_image + essential = true + cpu = 0 + portMappings = [{ + name = "frontend-8081-tcp" + containerPort = 8081 + hostPort = 8081 + protocol = "tcp" + appProtocol = "http" + }] + mountPoints = [ + { + sourceVolume = "MainApp" + containerPath = "/usr/share/nginx/html/MainApp/" + readOnly = false + } + ] + dependsOn = [ + { + containerName = "fastcgi" + condition = "START" + } + ] + }, + { + name = "backend" + image = var.aws_backend_image + essential = true + cpu = 0 + portMappings = [{ + name = "backend-8082-tcp" + containerPort = 8082 + hostPort = 8082 + protocol = "tcp" + appProtocol = "http" + }] + mountPoints = [ + { + sourceVolume = "files" + containerPath = "/usr/share/nginx/html/backend/files/" + readOnly = false + } + ] + dependsOn = [ + { + containerName = "fastcgi" + condition = "START" + } + ] + }, + { + name = "fastcgi" + image = var.aws_fastcgi_image + essential = true + cpu = 0 + portMappings = [{ + name = "fastcgi-9000-tcp" + containerPort = 9000 + hostPort = 9000 + protocol = "tcp" + }] + mountPoints = [ + { + sourceVolume = "MainApp" + containerPath = "/usr/share/nginx/html/MainApp/" + readOnly = false + }, + { + sourceVolume = "files" + containerPath = "/usr/share/nginx/html/backend/files/" + readOnly = false + } + ] + } + ]) +} + +resource "aws_ecs_cluster" "cloud_a_cluster" { + name = "seg-cloud-a-cluster" +} + +resource "aws_security_group" "allow_all" { + name = "seg-allow-all-sg" + description = "Allow all inbound traffic from VPC and all outbound traffic" + vpc_id = local.volt_vpc_id + # must keep this in-line definition (and not use aws_vpc_security_group_*gress_rule). + # Otherwise, dependencies may create the aws_ecs_service before the + # aws_vpc_security_group_*gress_rule and prevent the container from being pulled + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [var.aws_vpc_cidr] + } +} + +resource "aws_ecs_service" "cloud_a_service" { + name = "seg-cloud-a-service" + cluster = aws_ecs_cluster.cloud_a_cluster.id + task_definition = aws_ecs_task_definition.cloud_a_task.arn + desired_count = 1 + # required to allow tracking of the deployed container's IP + # (https://stackoverflow.com/questions/75856201/how-to-retrieve-the-public-ip-address-of-an-aws-ecs-contrainer-using-terraform) + enable_ecs_managed_tags = true + wait_for_steady_state = true + + network_configuration { + subnets = [local.workload_subnet_id] + assign_public_ip = false + security_groups = [aws_security_group.allow_all.id] + } + + capacity_provider_strategy { + capacity_provider = "FARGATE" + weight = 1 + base = 0 + } + +} diff --git a/terraform/data.tf b/terraform/data.tf new file mode 100644 index 0000000..5610df9 --- /dev/null +++ b/terraform/data.tf @@ -0,0 +1,13 @@ +// aws.tf DATA +data "aws_network_interface" "interface_tags" { + filter { + name = "tag:aws:ecs:serviceName" + values = [aws_ecs_service.cloud_a_service.name] + } +} + +// xc.tf DATA +data "volterra_http_loadbalancer_state" "cloud_a_lb_state" { + name = volterra_http_loadbalancer.cloud_a.name + namespace = volterra_http_loadbalancer.cloud_a.namespace +} diff --git a/terraform/delete_record_infomaniak_dns.ps1 b/terraform/delete_record_infomaniak_dns.ps1 new file mode 100644 index 0000000..b7ec3f3 --- /dev/null +++ b/terraform/delete_record_infomaniak_dns.ps1 @@ -0,0 +1,15 @@ +Write-Output "Deleting domain $env:INFK_SUBDOMAIN.$env:INFK_DOMAIN" + +$domain_id = (curl --silent --request GET ` + --url "https://api.infomaniak.com/1/product?service_name=domain&customer_name=$env:INFK_DOMAIN" ` + --header "Authorization: Bearer $env:INFK_TOKEN" | ConvertFrom-Json).data[0].id + +$record_id = ((curl --silent --request GET ` + --url https://api.infomaniak.com/1/domain/$domain_id/dns/record ` + --header "Authorization: Bearer $env:INFK_TOKEN" | ConvertFrom-JSON).data | Where-Object source -eq "$env:INFK_SUBDOMAIN").id + +$res = curl --silent --request DELETE ` + --url https://api.infomaniak.com/1/domain/$domain_id/dns/record/$record_id ` + --header "Authorization: Bearer $env:INFK_TOKEN" + +return $res \ No newline at end of file diff --git a/terraform/env.ps1.example b/terraform/env.ps1.example new file mode 100644 index 0000000..e2b6831 --- /dev/null +++ b/terraform/env.ps1.example @@ -0,0 +1,2 @@ +$env:VES_P12_PASSWORD="CHANGE_ME" +$env:INFK_TOKEN="CHANGE_ME" \ No newline at end of file diff --git a/terraform/env.sh.example b/terraform/env.sh.example new file mode 100644 index 0000000..b478b10 --- /dev/null +++ b/terraform/env.sh.example @@ -0,0 +1,2 @@ +export VES_P12_PASSWORD="CHANGE_ME" +export INFK_TOKEN="CHANGE_ME" \ No newline at end of file diff --git a/terraform/locals.tf b/terraform/locals.tf new file mode 100644 index 0000000..7b65367 --- /dev/null +++ b/terraform/locals.tf @@ -0,0 +1,11 @@ +locals { + app_fqdn = format("%s.%s", var.app_subdomain, var.app_domain) + cloud_b_domain = format("%s.%s", var.cloud_b_subdomain, local.app_fqdn) + cloud_c_domain = format("%s.%s", var.cloud_c_subdomain, local.app_fqdn) + cloud_a_service_private_ip = data.aws_network_interface.interface_tags.private_ip + # retrieves the aws workload subnet id created from the tf_output returned by aws to xc. + workload_subnet_id = jsondecode(regexall("subnet_info = (.*)", volterra_tf_params_action.apply_aws_vpc.tf_output)[0][0])[0].workload_subnet.id + # catches the created vpc id from the tf_output returned during the site creation by xc + volt_vpc_id = regexall("volt_vpc_id = \"(.*)\"", volterra_tf_params_action.apply_aws_vpc.tf_output)[0][0] + aws_ce_instance_private_ip = jsondecode(regexall("controller_dp_private_sli_ips = (.*)", volterra_tf_params_action.apply_aws_vpc.tf_output)[0][0])[0] +} diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..00ce0c3 --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,24 @@ +terraform { + required_providers { + volterra = { + source = "volterraedge/volterra" + version = "0.11.37" + } + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +provider "volterra" { + api_p12_file = var.api_cert + url = var.api_url +} + +# Configure the AWS Provider +provider "aws" { + region = "eu-central-1" + access_key = var.aws_ecs_access_key + secret_key = var.aws_ecs_secret_key +} diff --git a/terraform/outputs.tf b/terraform/outputs.tf new file mode 100644 index 0000000..99c419c --- /dev/null +++ b/terraform/outputs.tf @@ -0,0 +1,21 @@ +// aws.tf OUTPUTS +output "ecs_container_private_ip" { + value = local.cloud_a_service_private_ip +} + +output "aws_site_creation_tf_output" { + value = volterra_tf_params_action.apply_aws_vpc.tf_output +} + +output "aws_customer_edge_private_ip_on_aws" { + value = local.aws_ce_instance_private_ip +} + +// xc.tf OUTPUTS +output "lb_virtual_host" { + value = volterra_http_loadbalancer.cloud_a.cname +} + +output "lb_state" { + value = data.volterra_http_loadbalancer_state.cloud_a_lb_state +} diff --git a/terraform/terraform.tfvars.example b/terraform/terraform.tfvars.example new file mode 100644 index 0000000..456bb43 --- /dev/null +++ b/terraform/terraform.tfvars.example @@ -0,0 +1,5 @@ +aws_f5xc_access_key = "CHANGE_ME" +aws_f5xc_secret_key_blindfolded = "CHANGE_ME" +aws_ssh_key = "CHANGE_ME" +aws_ecs_access_key = "CHANGE_ME" +aws_ecs_secret_key = "CHANGE_ME" diff --git a/terraform/update_record_infomaniak_dns.ps1 b/terraform/update_record_infomaniak_dns.ps1 new file mode 100644 index 0000000..3e1e1ea --- /dev/null +++ b/terraform/update_record_infomaniak_dns.ps1 @@ -0,0 +1,22 @@ +Write-Output "Adding record for domain $env:INFK_SUBDOMAIN.$env:INFK_DOMAIN to target $env:INFK_TARGET" + +$domain_id = (curl --silent --request GET ` + --url "https://api.infomaniak.com/1/product?service_name=domain&customer_name=$env:INFK_DOMAIN" ` + --header "Authorization: Bearer $env:INFK_TOKEN" | ConvertFrom-Json).data[0].id + +$request_data = @" +{ + "type": "$env:INFK_RECORD_TYPE", + "source": "$env:INFK_SUBDOMAIN", + "target": "$env:INFK_TARGET", + "ttl": 300 +} +"@ + +$res = curl --silent --request POST ` + --url "https://api.infomaniak.com/1/domain/$domain_id/dns/record" ` + --header "Authorization: Bearer $env:INFK_TOKEN" ` + --header "Content-Type: application/json" ` + --data $request_data + +return $res \ No newline at end of file diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..d0d2725 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,106 @@ +// F5XC VARIABLES +variable "api_cert" { + type = string + default = "e-xpertsolutions.console.ves.volterra.io.api-creds.p12" +} + +variable "api_url" { + type = string + default = "https://e-xpertsolutions.console.ves.volterra.io/api" +} + +variable "namespace" { + type = string + default = "seg360-2024-demo" +} + +variable "tenant" { + type = string + default = "e-xpertsolutions-moyijavn" +} + +variable "app_subdomain" { + type = string + default = "tde-seg" +} + +variable "app_domain" { + type = string + default = "e-xpertsolutions.net" +} + +variable "cloud_b_subdomain" { + type = string + default = "friends" +} + +variable "cloud_c_subdomain" { + type = string + default = "transfer" +} + +variable "on_prem_site" { + type = string + default = "tde-seg-ce-vmware-gve" +} + +// AWS VARIABLES +variable "aws_ssh_key" { + type = string + sensitive = true +} + +variable "aws_f5xc_access_key" { + type = string + sensitive = true +} + +variable "aws_f5xc_secret_key_blindfolded" { + type = string + sensitive = true +} + +variable "aws_ecs_access_key" { + type = string + sensitive = true +} + +variable "aws_ecs_secret_key" { + type = string + sensitive = true +} + +variable "aws_region" { + type = string + default = "eu-central-1" +} + +variable "aws_vpc_cidr" { + type = string + default = "10.20.0.0/16" +} + +variable "aws_az" { + type = string + default = "eu-central-1a" +} + +variable "aws_reverse_proxy_image" { + type = string + default = "public.ecr.aws/t0m8o0y8/tde-seg-reverse-proxy" +} + +variable "aws_frontend_image" { + type = string + default = "public.ecr.aws/t0m8o0y8/tde-seg-frontend" +} + +variable "aws_backend_image" { + type = string + default = "public.ecr.aws/t0m8o0y8/tde-seg-backend" +} + +variable "aws_fastcgi_image" { + type = string + default = "public.ecr.aws/t0m8o0y8/tde-seg-fastcgi" +} diff --git a/terraform/xc.tf b/terraform/xc.tf new file mode 100644 index 0000000..0992c4c --- /dev/null +++ b/terraform/xc.tf @@ -0,0 +1,286 @@ +// TAG THE EXISTING ON-PREM SITE +resource "volterra_modify_site" "tde_seg_ce_vmware_gve" { + name = var.on_prem_site + namespace = "system" +} + +// HEALTHCHECK DEFINITION +resource "volterra_healthcheck" "clouds" { + for_each = tomap({ + cloud_a = { + name = "A" + healthcheck_path = "/" + } + cloud_b = { + name = "B" + healthcheck_path = "/app3/index.php" + } + cloud_c = { + name = "C" + healthcheck_path = "/api/side_bar.php" + } + }) + description = format("Healthcheck for testing SEG Cloud %s's origin pools", each.value.name) + name = format("seg-cloud-%s-healthcheck", lower(each.value.name)) + namespace = var.namespace + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 1 + interval = 60 + http_health_check { + path = each.value.healthcheck_path + } +} + +// CLOUD-B and CLOUD-C ORIGIN POOL DEFINITION +resource "volterra_origin_pool" "cloud_b_c" { + for_each = tomap({ + cloud_b = { + name = "B" + port = 8080 + } + cloud_c = { + name = "C" + port = 8080 + } + }) + description = format("Origin pool for the Cloud %s services on premise", each.value.name) + name = format("seg-cloud-%s-op", lower(each.value.name)) + namespace = var.namespace + endpoint_selection = "LOCAL_PREFERRED" + loadbalancer_algorithm = "LB_OVERRIDE" + port = each.value.port + no_tls = true + + healthcheck { + name = volterra_healthcheck.clouds[each.key].name + namespace = volterra_healthcheck.clouds[each.key].namespace + tenant = var.tenant + } + + origin_servers { + k8s_service { + vk8s_networks = true + service_name = format("seg-vk8s-workload-cloud-%s.seg360-2024-demo", lower(each.value.name)) + site_locator { + site { + name = var.on_prem_site + namespace = "system" + tenant = var.tenant + } + } + } + } +} + +// CLOUD-A ORIGIN POOL DEFINITION +resource "volterra_origin_pool" "cloud_a" { + description = "Origin pool for the Cloud A's frontend service on AWS" + name = "seg-cloud-a-op" + namespace = var.namespace + endpoint_selection = "LOCAL_PREFERRED" + loadbalancer_algorithm = "LB_OVERRIDE" + port = 8080 + no_tls = true + + healthcheck { + name = volterra_healthcheck.clouds["cloud_a"].name + namespace = volterra_healthcheck.clouds["cloud_a"].namespace + tenant = var.tenant + } + + origin_servers { + private_ip { + ip = local.cloud_a_service_private_ip + inside_network = true + site_locator { + site { + name = volterra_aws_vpc_site.cloud_a_site.name + namespace = "system" + tenant = var.tenant + } + } + } + } +} + +// SERVICE POLICY FOR ALLOWING ONLY E-XPERT WAN IP +resource "volterra_service_policy" "allow_e_xpert_wan" { + description = "Policy to allow connections from internet only with e-Xpert owned WAN IPs" + name = "seg-allow-e-xpert-wan" + namespace = var.namespace + algo = "FIRST_MATCH" + any_server = true + allow_list { + prefix_list { + prefixes = ["46.14.179.0/27", "83.166.158.32/27", "81.63.137.43/32"] + ipv6_prefixes = [] + } + default_action_next_policy = true + } +} + +// WAF CONFIGURATION +resource "volterra_app_firewall" "seg_waf_config" { + description = "Basic WAF config for SEG demo application" + name = "seg-waf-config" + namespace = var.namespace + blocking = true + + // defaults + allow_all_response_codes = true + use_default_blocking_page = true + default_bot_setting = true + default_detection_settings = true + + custom_anonymization { + anonymization_config { + query_parameter { + // Masks the Signature query parameter of SAML Redirect + query_param_name = "Signature" + } + } + } +} + +// LOAD BALANCER FOR INTERNAL SERVICE ON-PREM ADVERTISED ON AWS +resource "volterra_http_loadbalancer" "cloud_b_c" { + description = "Load balancer for Cloud B and Cloud C's services advertised on Cloud A." + name = "seg-cloud-b-c-http-lb" + namespace = var.namespace + domains = [local.cloud_b_domain, local.cloud_c_domain] + + # despite being defaults, all these must be set, otherwise trigger change detection + service_policies_from_namespace = true + disable_api_definition = true + disable_api_discovery = true + disable_rate_limit = true + disable_trust_client_ip_headers = true + l7_ddos_action_default = true + no_challenge = true + round_robin = true + user_id_client_ip = true + disable_malicious_user_detection = true + + app_firewall { + name = volterra_app_firewall.seg_waf_config.name + namespace = volterra_app_firewall.seg_waf_config.namespace + tenant = var.tenant + } + + http { + # not supported for site advertised LB. Done manually but with TF + # dns_volterra_managed = true + port = 80 + } + + routes { + simple_route { + auto_host_rewrite = true + http_method = "ANY" + origin_pools { + pool { + name = volterra_origin_pool.cloud_b_c["cloud_b"].name + namespace = volterra_origin_pool.cloud_b_c["cloud_b"].namespace + tenant = var.tenant + } + weight = 1 + priority = 1 + } + path { + prefix = "/app3/" + } + } + } + + routes { + simple_route { + auto_host_rewrite = true + http_method = "ANY" + origin_pools { + pool { + name = volterra_origin_pool.cloud_b_c["cloud_c"].name + namespace = volterra_origin_pool.cloud_b_c["cloud_c"].namespace + tenant = var.tenant + } + weight = 1 + priority = 1 + } + path { + prefix = "/api/" + } + } + } + + + advertise_custom { + advertise_where { + use_default_port = true + site { + network = "SITE_NETWORK_INSIDE" + site { + name = volterra_aws_vpc_site.cloud_a_site.name + namespace = volterra_aws_vpc_site.cloud_a_site.namespace + tenant = var.tenant + } + } + } + } +} + +// CLIENT FACING HTTP LOAD BALANCER DEFINITION +resource "volterra_http_loadbalancer" "cloud_a" { + description = "Client facing load balancer for SEG360 demo application." + name = "seg-cloud-a-http-lb" + namespace = var.namespace + domains = [local.app_fqdn] + + # despite being defaults, all these must be set, otherwise trigger change detection + advertise_on_public_default_vip = true + disable_api_definition = true + disable_api_discovery = true + disable_rate_limit = true + disable_trust_client_ip_headers = true + l7_ddos_action_default = true + no_challenge = true + round_robin = true + user_id_client_ip = true + disable_malicious_user_detection = true + + app_firewall { + name = volterra_app_firewall.seg_waf_config.name + namespace = volterra_app_firewall.seg_waf_config.namespace + tenant = var.tenant + } + + https_auto_cert { + no_mtls = true + enable_path_normalize = true + port = 443 + } + + more_option { + request_headers_to_add { + name = "X-Forwarded-Host" + value = local.app_fqdn + } + } + default_route_pools { + pool { + name = volterra_origin_pool.cloud_a.name + namespace = volterra_origin_pool.cloud_a.namespace + tenant = var.tenant + } + # must be set as default value is 0 and disables the pool + weight = 1 + priority = 1 + } + + active_service_policies { + policies { + name = volterra_service_policy.allow_e_xpert_wan.name + namespace = volterra_service_policy.allow_e_xpert_wan.namespace + tenant = var.tenant + } + } +}