diff --git a/.gitignore b/.gitignore index daa30a3f752706bce3bc36b34a7aab39ee5484d4..e7dff43ac58af825e6105802266a6918f9c56e0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ README.html +id_* +*.pem +*.key \ No newline at end of file diff --git a/Ansible/ansible.cfg b/Ansible/ansible.cfg new file mode 100644 index 0000000000000000000000000000000000000000..ffb9bb537e268c6ca6c4dab2f33147ec3abe547f --- /dev/null +++ b/Ansible/ansible.cfg @@ -0,0 +1,7 @@ +[defaults] +inventory = hosts.yml +remote_user = terraform +private_key_file = keys/id_ed25519 +host_key_checking = false +deprecation_warnings = false +interpreter_python = auto_silent diff --git a/Ansible/hosts.yml b/Ansible/hosts.yml new file mode 100644 index 0000000000000000000000000000000000000000..ad77f8d33bc7e5efcb66dcd1d2b0a025721ffccb --- /dev/null +++ b/Ansible/hosts.yml @@ -0,0 +1,11 @@ +all: + hosts: + testserver: + ansible_ssh_host: '<your-VM-IP>' + + # aliases + tfserver: + testserver: + + project-web-sso: + testserver: diff --git a/Ansible/keys/README.md b/Ansible/keys/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3e6fdee4341b9ed6ff2eed7383080e2c4d07c241 --- /dev/null +++ b/Ansible/keys/README.md @@ -0,0 +1,2 @@ +Files dropped here with names "id_*" won't be committed -- see the top-level +.gitignore file. diff --git a/Ansible/playbooks/files/kind-config.yaml b/Ansible/playbooks/files/kind-config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..06b30293897715800a88bf470042eb7a3399d35a --- /dev/null +++ b/Ansible/playbooks/files/kind-config.yaml @@ -0,0 +1,31 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +# patch the generated kubeadm config with some extra settings +kubeadmConfigPatches: +- | + apiVersion: kubelet.config.k8s.io/v1beta1 + kind: KubeletConfiguration + evictionHard: + nodefs.available: "0%" +# patch it further using a JSON 6902 patch +kubeadmConfigPatchesJSON6902: +- group: kubeadm.k8s.io + version: v1beta3 + kind: ClusterConfiguration + patch: | + - op: add + path: /apiServer/certSANs/- + value: my-hostname + +# Comment in this to fix the API port so that you can use kubectl via an SSH +# tunnel started from the management machine with: +# $ ssh -L 6443:localhost:6443 <remote-kube-host> +# References: <https://github.com/kubernetes-sigs/kind/issues/3417#issuecomment-1806231832> +networking: + apiServerPort: 6443 + +nodes: +- role: control-plane +- role: worker + labels: + application: hepia-bachelor-web-sso diff --git a/Ansible/playbooks/files/lb-deployment.yaml b/Ansible/playbooks/files/lb-deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a05ea071992ce109bafc0c3417e8076158eef5f1 --- /dev/null +++ b/Ansible/playbooks/files/lb-deployment.yaml @@ -0,0 +1,41 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: http-echo +spec: + replicas: 2 + selector: + matchLabels: + app: http-echo + template: + metadata: + labels: + app: http-echo + spec: + nodeSelector: + kubernetes.io/hostname: kind-worker # Schedule pods on one worker node + containers: + - name: http-echo + image: hashicorp/http-echo + args: + - >- + -text=Hello from Kubernetes! My IP is $(POD_IP) + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + ports: + - containerPort: 5678 +--- +apiVersion: v1 +kind: Service +metadata: + name: loadbalancer +spec: + type: LoadBalancer + selector: + app: http-echo + ports: + - port: 80 + targetPort: 5678 diff --git a/Ansible/playbooks/files/metallb-native.yaml b/Ansible/playbooks/files/metallb-native.yaml new file mode 100644 index 0000000000000000000000000000000000000000..de6ca2118e31793c516e01d7999d0baf4b708fae --- /dev/null +++ b/Ansible/playbooks/files/metallb-native.yaml @@ -0,0 +1,2042 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + pod-security.kubernetes.io/audit: privileged + pod-security.kubernetes.io/enforce: privileged + pod-security.kubernetes.io/warn: privileged + name: metallb-system +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: addresspools.metallb.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlGWlRDQ0EwMmdBd0lCQWdJVU5GRW1XcTM3MVpKdGkrMmlSQzk1WmpBV1MxZ3dEUVlKS29aSWh2Y05BUUVMDQpCUUF3UWpFTE1Ba0dBMVVFQmhNQ1dGZ3hGVEFUQmdOVkJBY01ERVJsWm1GMWJIUWdRMmwwZVRFY01Cb0dBMVVFDQpDZ3dUUkdWbVlYVnNkQ0JEYjIxd1lXNTVJRXgwWkRBZUZ3MHlNakEzTVRrd09UTXlNek5hRncweU1qQTRNVGd3DQpPVE15TXpOYU1FSXhDekFKQmdOVkJBWVRBbGhZTVJVd0V3WURWUVFIREF4RVpXWmhkV3gwSUVOcGRIa3hIREFhDQpCZ05WQkFvTUUwUmxabUYxYkhRZ1EyOXRjR0Z1ZVNCTWRHUXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDDQpEd0F3Z2dJS0FvSUNBUUNxVFpxMWZRcC9vYkdlenhES0o3OVB3Ny94azJwellualNzMlkzb1ZYSm5sRmM4YjVlDQpma2ZZQnY2bndscW1keW5PL2phWFBaQmRQSS82aFdOUDBkdVhadEtWU0NCUUpyZzEyOGNXb3F0MGNTN3pLb1VpDQpvcU1tQ0QvRXVBeFFNZjhRZDF2c1gvVllkZ0poVTZBRXJLZEpIaXpFOUJtUkNkTDBGMW1OVW55Rk82UnRtWFZUDQpidkxsTDVYeTc2R0FaQVBLOFB4aVlDa0NtbDdxN0VnTWNiOXlLWldCYmlxQ3VkTXE5TGJLNmdKNzF6YkZnSXV4DQo1L1pXK2JraTB2RlplWk9ZODUxb1psckFUNzJvMDI4NHNTWW9uN0pHZVZkY3NoUnh5R1VpSFpSTzdkaXZVTDVTDQpmM2JmSDFYbWY1ZDQzT0NWTWRuUUV2NWVaOG8zeWVLa3ZrbkZQUGVJMU9BbjdGbDlFRVNNR2dhOGFaSG1URSttDQpsLzlMSmdDYjBnQmtPT0M0WnV4bWh2aERKV1EzWnJCS3pMQlNUZXN0NWlLNVlwcXRWVVk2THRyRW9FelVTK1lsDQpwWndXY2VQWHlHeHM5ZURsR3lNVmQraW15Y3NTU1UvVno2Mmx6MnZCS21NTXBkYldDQWhud0RsRTVqU2dyMjRRDQp0eGNXLys2N3d5KzhuQlI3UXdqVTFITndVRjBzeERWdEwrZ1NHVERnSEVZSlhZelYvT05zMy94TkpoVFNPSkxNDQpoeXNVdyttaGdackdhbUdXcHVIVU1DUitvTWJzMTc1UkcrQjJnUFFHVytPTjJnUTRyOXN2b0ZBNHBBQm8xd1dLDQpRYjRhY3pmeVVscElBOVFoSmFsZEY3S3dPSHVlV3gwRUNrNXg0T2tvVDBvWVp0dzFiR0JjRGtaSmF3SURBUUFCDQpvMU13VVRBZEJnTlZIUTRFRmdRVW90UlNIUm9IWTEyRFZ4R0NCdEhpb1g2ZmVFQXdId1lEVlIwakJCZ3dGb0FVDQpvdFJTSFJvSFkxMkRWeEdDQnRIaW9YNmZlRUF3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCDQpBUXNGQUFPQ0FnRUFSbkpsWWRjMTFHd0VxWnh6RDF2R3BDR2pDN2VWTlQ3aVY1d3IybXlybHdPYi9aUWFEa0xYDQpvVStaOVVXT1VlSXJTdzUydDdmQUpvVVAwSm5iYkMveVIrU1lqUGhvUXNiVHduOTc2ZldBWTduM3FMOXhCd1Y0DQphek41OXNjeUp0dlhMeUtOL2N5ak1ReDRLajBIMFg0bWJ6bzVZNUtzWWtYVU0vOEFPdWZMcEd0S1NGVGgrSEFDDQpab1Q5YnZHS25adnNHd0tYZFF0Wnh0akhaUjVqK3U3ZGtQOTJBT051RFNabS8rWVV4b2tBK09JbzdSR3BwSHNXDQo1ZTdNY0FTVXRtb1FORXd6dVFoVkJaRWQ1OGtKYjUrV0VWbGNzanlXNnRTbzErZ25tTWNqR1BsMWgxR2hVbjV4DQpFY0lWRnBIWXM5YWo1NmpBSjk1MVQvZjhMaWxmTlVnanBLQ0c1bnl0SUt3emxhOHNtdGlPdm1UNEpYbXBwSkI2DQo4bmdHRVluVjUrUTYwWFJ2OEhSSGp1VG9CRHVhaERrVDA2R1JGODU1d09FR2V4bkZpMXZYWUxLVllWb1V2MXRKDQo4dVdUR1pwNllDSVJldlBqbzg5ZytWTlJSaVFYUThJd0dybXE5c0RoVTlqTjA0SjdVL1RvRDFpNHE3VnlsRUc5DQorV1VGNkNLaEdBeTJIaEhwVncyTGFoOS9lUzdZMUZ1YURrWmhPZG1laG1BOCtqdHNZamJadnR5Mm1SWlF0UUZzDQpUU1VUUjREbUR2bVVPRVRmeStpRHdzK2RkWXVNTnJGeVVYV2dkMnpBQU4ydVl1UHFGY2pRcFNPODFzVTJTU3R3DQoxVzAyeUtYOGJEYmZFdjBzbUh3UzliQnFlSGo5NEM1Mjg0YXpsdTBmaUdpTm1OUEM4ckJLRmhBPQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ== + service: + name: webhook-service + namespace: metallb-system + path: /convert + conversionReviewVersions: + - v1alpha1 + - v1beta1 + group: metallb.io + names: + kind: AddressPool + listKind: AddressPoolList + plural: addresspools + singular: addresspool + scope: Namespaced + versions: + - deprecated: true + deprecationWarning: metallb.io v1alpha1 AddressPool is deprecated + name: v1alpha1 + schema: + openAPIV3Schema: + description: AddressPool is the Schema for the addresspools API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AddressPoolSpec defines the desired state of AddressPool. + properties: + addresses: + description: A list of IP address ranges over which MetalLB has authority. + You can list multiple ranges in a single pool, they will all share + the same settings. Each range can be either a CIDR prefix, or an + explicit start-end range of IPs. + items: + type: string + type: array + autoAssign: + default: true + description: AutoAssign flag used to prevent MetallB from automatic + allocation for a pool. + type: boolean + bgpAdvertisements: + description: When an IP is allocated from this pool, how should it + be translated into BGP announcements? + items: + properties: + aggregationLength: + default: 32 + description: The aggregation-length advertisement option lets + you “roll up” the /32s into a larger prefix. + format: int32 + minimum: 1 + type: integer + aggregationLengthV6: + default: 128 + description: Optional, defaults to 128 (i.e. no aggregation) + if not specified. + format: int32 + type: integer + communities: + description: BGP communities + items: + type: string + type: array + localPref: + description: BGP LOCAL_PREF attribute which is used by BGP best + path algorithm, Path with higher localpref is preferred over + one with lower localpref. + format: int32 + type: integer + type: object + type: array + protocol: + description: Protocol can be used to select how the announcement is + done. + enum: + - layer2 + - bgp + type: string + required: + - addresses + - protocol + type: object + status: + description: AddressPoolStatus defines the observed state of AddressPool. + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} + - deprecated: true + deprecationWarning: metallb.io v1beta1 AddressPool is deprecated, consider using + IPAddressPool + name: v1beta1 + schema: + openAPIV3Schema: + description: AddressPool represents a pool of IP addresses that can be allocated + to LoadBalancer services. AddressPool is deprecated and being replaced by + IPAddressPool. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AddressPoolSpec defines the desired state of AddressPool. + properties: + addresses: + description: A list of IP address ranges over which MetalLB has authority. + You can list multiple ranges in a single pool, they will all share + the same settings. Each range can be either a CIDR prefix, or an + explicit start-end range of IPs. + items: + type: string + type: array + autoAssign: + default: true + description: AutoAssign flag used to prevent MetallB from automatic + allocation for a pool. + type: boolean + bgpAdvertisements: + description: Drives how an IP allocated from this pool should translated + into BGP announcements. + items: + properties: + aggregationLength: + default: 32 + description: The aggregation-length advertisement option lets + you “roll up” the /32s into a larger prefix. + format: int32 + minimum: 1 + type: integer + aggregationLengthV6: + default: 128 + description: Optional, defaults to 128 (i.e. no aggregation) + if not specified. + format: int32 + type: integer + communities: + description: BGP communities to be associated with the given + advertisement. + items: + type: string + type: array + localPref: + description: BGP LOCAL_PREF attribute which is used by BGP best + path algorithm, Path with higher localpref is preferred over + one with lower localpref. + format: int32 + type: integer + type: object + type: array + protocol: + description: Protocol can be used to select how the announcement is + done. + enum: + - layer2 + - bgp + type: string + required: + - addresses + - protocol + type: object + status: + description: AddressPoolStatus defines the observed state of AddressPool. + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: bfdprofiles.metallb.io +spec: + group: metallb.io + names: + kind: BFDProfile + listKind: BFDProfileList + plural: bfdprofiles + singular: bfdprofile + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.passiveMode + name: Passive Mode + type: boolean + - jsonPath: .spec.transmitInterval + name: Transmit Interval + type: integer + - jsonPath: .spec.receiveInterval + name: Receive Interval + type: integer + - jsonPath: .spec.detectMultiplier + name: Multiplier + type: integer + name: v1beta1 + schema: + openAPIV3Schema: + description: BFDProfile represents the settings of the bfd session that can + be optionally associated with a BGP session. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BFDProfileSpec defines the desired state of BFDProfile. + properties: + detectMultiplier: + description: Configures the detection multiplier to determine packet + loss. The remote transmission interval will be multiplied by this + value to determine the connection loss detection timer. + format: int32 + maximum: 255 + minimum: 2 + type: integer + echoInterval: + description: Configures the minimal echo receive transmission interval + that this system is capable of handling in milliseconds. Defaults + to 50ms + format: int32 + maximum: 60000 + minimum: 10 + type: integer + echoMode: + description: Enables or disables the echo transmission mode. This + mode is disabled by default, and not supported on multi hops setups. + type: boolean + minimumTtl: + description: 'For multi hop sessions only: configure the minimum expected + TTL for an incoming BFD control packet.' + format: int32 + maximum: 254 + minimum: 1 + type: integer + passiveMode: + description: 'Mark session as passive: a passive session will not + attempt to start the connection and will wait for control packets + from peer before it begins replying.' + type: boolean + receiveInterval: + description: The minimum interval that this system is capable of receiving + control packets in milliseconds. Defaults to 300ms. + format: int32 + maximum: 60000 + minimum: 10 + type: integer + transmitInterval: + description: The minimum transmission interval (less jitter) that + this system wants to use to send BFD control packets in milliseconds. + Defaults to 300ms + format: int32 + maximum: 60000 + minimum: 10 + type: integer + type: object + status: + description: BFDProfileStatus defines the observed state of BFDProfile. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: bgpadvertisements.metallb.io +spec: + group: metallb.io + names: + kind: BGPAdvertisement + listKind: BGPAdvertisementList + plural: bgpadvertisements + singular: bgpadvertisement + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.ipAddressPools + name: IPAddressPools + type: string + - jsonPath: .spec.ipAddressPoolSelectors + name: IPAddressPool Selectors + type: string + - jsonPath: .spec.peers + name: Peers + type: string + - jsonPath: .spec.nodeSelectors + name: Node Selectors + priority: 10 + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: BGPAdvertisement allows to advertise the IPs coming from the + selected IPAddressPools via BGP, setting the parameters of the BGP Advertisement. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BGPAdvertisementSpec defines the desired state of BGPAdvertisement. + properties: + aggregationLength: + default: 32 + description: The aggregation-length advertisement option lets you + “roll up” the /32s into a larger prefix. Defaults to 32. Works for + IPv4 addresses. + format: int32 + minimum: 1 + type: integer + aggregationLengthV6: + default: 128 + description: The aggregation-length advertisement option lets you + “roll up” the /128s into a larger prefix. Defaults to 128. Works + for IPv6 addresses. + format: int32 + type: integer + communities: + description: The BGP communities to be associated with the announcement. + Each item can be a standard community of the form 1234:1234, a large + community of the form large:1234:1234:1234 or the name of an alias + defined in the Community CRD. + items: + type: string + type: array + ipAddressPoolSelectors: + description: A selector for the IPAddressPools which would get advertised + via this advertisement. If no IPAddressPool is selected by this + or by the list, the advertisement is applied to all the IPAddressPools. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + ipAddressPools: + description: The list of IPAddressPools to advertise via this advertisement, + selected by name. + items: + type: string + type: array + localPref: + description: The BGP LOCAL_PREF attribute which is used by BGP best + path algorithm, Path with higher localpref is preferred over one + with lower localpref. + format: int32 + type: integer + nodeSelectors: + description: NodeSelectors allows to limit the nodes to announce as + next hops for the LoadBalancer IP. When empty, all the nodes having are + announced as next hops. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + peers: + description: Peers limits the bgppeer to advertise the ips of the + selected pools to. When empty, the loadbalancer IP is announced + to all the BGPPeers configured. + items: + type: string + type: array + type: object + status: + description: BGPAdvertisementStatus defines the observed state of BGPAdvertisement. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: bgppeers.metallb.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlGWlRDQ0EwMmdBd0lCQWdJVU5GRW1XcTM3MVpKdGkrMmlSQzk1WmpBV1MxZ3dEUVlKS29aSWh2Y05BUUVMDQpCUUF3UWpFTE1Ba0dBMVVFQmhNQ1dGZ3hGVEFUQmdOVkJBY01ERVJsWm1GMWJIUWdRMmwwZVRFY01Cb0dBMVVFDQpDZ3dUUkdWbVlYVnNkQ0JEYjIxd1lXNTVJRXgwWkRBZUZ3MHlNakEzTVRrd09UTXlNek5hRncweU1qQTRNVGd3DQpPVE15TXpOYU1FSXhDekFKQmdOVkJBWVRBbGhZTVJVd0V3WURWUVFIREF4RVpXWmhkV3gwSUVOcGRIa3hIREFhDQpCZ05WQkFvTUUwUmxabUYxYkhRZ1EyOXRjR0Z1ZVNCTWRHUXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDDQpEd0F3Z2dJS0FvSUNBUUNxVFpxMWZRcC9vYkdlenhES0o3OVB3Ny94azJwellualNzMlkzb1ZYSm5sRmM4YjVlDQpma2ZZQnY2bndscW1keW5PL2phWFBaQmRQSS82aFdOUDBkdVhadEtWU0NCUUpyZzEyOGNXb3F0MGNTN3pLb1VpDQpvcU1tQ0QvRXVBeFFNZjhRZDF2c1gvVllkZ0poVTZBRXJLZEpIaXpFOUJtUkNkTDBGMW1OVW55Rk82UnRtWFZUDQpidkxsTDVYeTc2R0FaQVBLOFB4aVlDa0NtbDdxN0VnTWNiOXlLWldCYmlxQ3VkTXE5TGJLNmdKNzF6YkZnSXV4DQo1L1pXK2JraTB2RlplWk9ZODUxb1psckFUNzJvMDI4NHNTWW9uN0pHZVZkY3NoUnh5R1VpSFpSTzdkaXZVTDVTDQpmM2JmSDFYbWY1ZDQzT0NWTWRuUUV2NWVaOG8zeWVLa3ZrbkZQUGVJMU9BbjdGbDlFRVNNR2dhOGFaSG1URSttDQpsLzlMSmdDYjBnQmtPT0M0WnV4bWh2aERKV1EzWnJCS3pMQlNUZXN0NWlLNVlwcXRWVVk2THRyRW9FelVTK1lsDQpwWndXY2VQWHlHeHM5ZURsR3lNVmQraW15Y3NTU1UvVno2Mmx6MnZCS21NTXBkYldDQWhud0RsRTVqU2dyMjRRDQp0eGNXLys2N3d5KzhuQlI3UXdqVTFITndVRjBzeERWdEwrZ1NHVERnSEVZSlhZelYvT05zMy94TkpoVFNPSkxNDQpoeXNVdyttaGdackdhbUdXcHVIVU1DUitvTWJzMTc1UkcrQjJnUFFHVytPTjJnUTRyOXN2b0ZBNHBBQm8xd1dLDQpRYjRhY3pmeVVscElBOVFoSmFsZEY3S3dPSHVlV3gwRUNrNXg0T2tvVDBvWVp0dzFiR0JjRGtaSmF3SURBUUFCDQpvMU13VVRBZEJnTlZIUTRFRmdRVW90UlNIUm9IWTEyRFZ4R0NCdEhpb1g2ZmVFQXdId1lEVlIwakJCZ3dGb0FVDQpvdFJTSFJvSFkxMkRWeEdDQnRIaW9YNmZlRUF3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCDQpBUXNGQUFPQ0FnRUFSbkpsWWRjMTFHd0VxWnh6RDF2R3BDR2pDN2VWTlQ3aVY1d3IybXlybHdPYi9aUWFEa0xYDQpvVStaOVVXT1VlSXJTdzUydDdmQUpvVVAwSm5iYkMveVIrU1lqUGhvUXNiVHduOTc2ZldBWTduM3FMOXhCd1Y0DQphek41OXNjeUp0dlhMeUtOL2N5ak1ReDRLajBIMFg0bWJ6bzVZNUtzWWtYVU0vOEFPdWZMcEd0S1NGVGgrSEFDDQpab1Q5YnZHS25adnNHd0tYZFF0Wnh0akhaUjVqK3U3ZGtQOTJBT051RFNabS8rWVV4b2tBK09JbzdSR3BwSHNXDQo1ZTdNY0FTVXRtb1FORXd6dVFoVkJaRWQ1OGtKYjUrV0VWbGNzanlXNnRTbzErZ25tTWNqR1BsMWgxR2hVbjV4DQpFY0lWRnBIWXM5YWo1NmpBSjk1MVQvZjhMaWxmTlVnanBLQ0c1bnl0SUt3emxhOHNtdGlPdm1UNEpYbXBwSkI2DQo4bmdHRVluVjUrUTYwWFJ2OEhSSGp1VG9CRHVhaERrVDA2R1JGODU1d09FR2V4bkZpMXZYWUxLVllWb1V2MXRKDQo4dVdUR1pwNllDSVJldlBqbzg5ZytWTlJSaVFYUThJd0dybXE5c0RoVTlqTjA0SjdVL1RvRDFpNHE3VnlsRUc5DQorV1VGNkNLaEdBeTJIaEhwVncyTGFoOS9lUzdZMUZ1YURrWmhPZG1laG1BOCtqdHNZamJadnR5Mm1SWlF0UUZzDQpUU1VUUjREbUR2bVVPRVRmeStpRHdzK2RkWXVNTnJGeVVYV2dkMnpBQU4ydVl1UHFGY2pRcFNPODFzVTJTU3R3DQoxVzAyeUtYOGJEYmZFdjBzbUh3UzliQnFlSGo5NEM1Mjg0YXpsdTBmaUdpTm1OUEM4ckJLRmhBPQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ== + service: + name: webhook-service + namespace: metallb-system + path: /convert + conversionReviewVersions: + - v1beta1 + - v1beta2 + group: metallb.io + names: + kind: BGPPeer + listKind: BGPPeerList + plural: bgppeers + singular: bgppeer + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.peerAddress + name: Address + type: string + - jsonPath: .spec.peerASN + name: ASN + type: string + - jsonPath: .spec.bfdProfile + name: BFD Profile + type: string + - jsonPath: .spec.ebgpMultiHop + name: Multi Hops + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: BGPPeer is the Schema for the peers API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BGPPeerSpec defines the desired state of Peer. + properties: + bfdProfile: + type: string + ebgpMultiHop: + description: EBGP peer is multi-hops away + type: boolean + holdTime: + description: Requested BGP hold time, per RFC4271. + type: string + keepaliveTime: + description: Requested BGP keepalive time, per RFC4271. + type: string + myASN: + description: AS number to use for the local end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + nodeSelectors: + description: Only connect to this peer on nodes that match one of + these selectors. + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + minItems: 1 + type: array + required: + - key + - operator + - values + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: array + password: + description: Authentication password for routers enforcing TCP MD5 + authenticated sessions + type: string + peerASN: + description: AS number to expect from the remote end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + peerAddress: + description: Address to dial when establishing the session. + type: string + peerPort: + description: Port to dial when establishing the session. + maximum: 16384 + minimum: 0 + type: integer + routerID: + description: BGP router ID to advertise to the peer + type: string + sourceAddress: + description: Source address to use when establishing the session. + type: string + required: + - myASN + - peerASN + - peerAddress + type: object + status: + description: BGPPeerStatus defines the observed state of Peer. + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.peerAddress + name: Address + type: string + - jsonPath: .spec.peerASN + name: ASN + type: string + - jsonPath: .spec.bfdProfile + name: BFD Profile + type: string + - jsonPath: .spec.ebgpMultiHop + name: Multi Hops + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: BGPPeer is the Schema for the peers API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BGPPeerSpec defines the desired state of Peer. + properties: + bfdProfile: + description: The name of the BFD Profile to be used for the BFD session + associated to the BGP session. If not set, the BFD session won't + be set up. + type: string + ebgpMultiHop: + description: To set if the BGPPeer is multi-hops away. Needed for + FRR mode only. + type: boolean + holdTime: + description: Requested BGP hold time, per RFC4271. + type: string + keepaliveTime: + description: Requested BGP keepalive time, per RFC4271. + type: string + myASN: + description: AS number to use for the local end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + nodeSelectors: + description: Only connect to this peer on nodes that match one of + these selectors. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + password: + description: Authentication password for routers enforcing TCP MD5 + authenticated sessions + type: string + passwordSecret: + description: passwordSecret is name of the authentication secret for + BGP Peer. the secret must be of type "kubernetes.io/basic-auth", + and created in the same namespace as the MetalLB deployment. The + password is stored in the secret as the key "password". + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + peerASN: + description: AS number to expect from the remote end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + peerAddress: + description: Address to dial when establishing the session. + type: string + peerPort: + default: 179 + description: Port to dial when establishing the session. + maximum: 16384 + minimum: 0 + type: integer + routerID: + description: BGP router ID to advertise to the peer + type: string + sourceAddress: + description: Source address to use when establishing the session. + type: string + vrf: + description: To set if we want to peer with the BGPPeer using an interface + belonging to a host vrf + type: string + required: + - myASN + - peerASN + - peerAddress + type: object + status: + description: BGPPeerStatus defines the observed state of Peer. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: communities.metallb.io +spec: + group: metallb.io + names: + kind: Community + listKind: CommunityList + plural: communities + singular: community + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: Community is a collection of aliases for communities. Users can + define named aliases to be used in the BGPPeer CRD. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: CommunitySpec defines the desired state of Community. + properties: + communities: + items: + properties: + name: + description: The name of the alias for the community. + type: string + value: + description: The BGP community value corresponding to the given + name. Can be a standard community of the form 1234:1234 or + a large community of the form large:1234:1234:1234. + type: string + type: object + type: array + type: object + status: + description: CommunityStatus defines the observed state of Community. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: ipaddresspools.metallb.io +spec: + group: metallb.io + names: + kind: IPAddressPool + listKind: IPAddressPoolList + plural: ipaddresspools + singular: ipaddresspool + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.autoAssign + name: Auto Assign + type: boolean + - jsonPath: .spec.avoidBuggyIPs + name: Avoid Buggy IPs + type: boolean + - jsonPath: .spec.addresses + name: Addresses + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: IPAddressPool represents a pool of IP addresses that can be allocated + to LoadBalancer services. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: IPAddressPoolSpec defines the desired state of IPAddressPool. + properties: + addresses: + description: A list of IP address ranges over which MetalLB has authority. + You can list multiple ranges in a single pool, they will all share + the same settings. Each range can be either a CIDR prefix, or an + explicit start-end range of IPs. + items: + type: string + type: array + autoAssign: + default: true + description: AutoAssign flag used to prevent MetallB from automatic + allocation for a pool. + type: boolean + avoidBuggyIPs: + default: false + description: AvoidBuggyIPs prevents addresses ending with .0 and .255 + to be used by a pool. + type: boolean + serviceAllocation: + description: AllocateTo makes ip pool allocation to specific namespace + and/or service. The controller will use the pool with lowest value + of priority in case of multiple matches. A pool with no priority + set will be used only if the pools with priority can't be used. + If multiple matching IPAddressPools are available it will check + for the availability of IPs sorting the matching IPAddressPools + by priority, starting from the highest to the lowest. If multiple + IPAddressPools have the same priority, choice will be random. + properties: + namespaceSelectors: + description: NamespaceSelectors list of label selectors to select + namespace(s) for ip pool, an alternative to using namespace + list. + items: + description: A label selector is a label query over a set of + resources. The result of matchLabels and matchExpressions + are ANDed. An empty label selector matches all objects. A + null label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. This + array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is + "key", the operator is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + namespaces: + description: Namespaces list of namespace(s) on which ip pool + can be attached. + items: + type: string + type: array + priority: + description: Priority priority given for ip pool while ip allocation + on a service. + type: integer + serviceSelectors: + description: ServiceSelectors list of label selector to select + service(s) for which ip pool can be used for ip allocation. + items: + description: A label selector is a label query over a set of + resources. The result of matchLabels and matchExpressions + are ANDed. An empty label selector matches all objects. A + null label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. This + array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is + "key", the operator is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + type: object + required: + - addresses + type: object + status: + description: IPAddressPoolStatus defines the observed state of IPAddressPool. + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: l2advertisements.metallb.io +spec: + group: metallb.io + names: + kind: L2Advertisement + listKind: L2AdvertisementList + plural: l2advertisements + singular: l2advertisement + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.ipAddressPools + name: IPAddressPools + type: string + - jsonPath: .spec.ipAddressPoolSelectors + name: IPAddressPool Selectors + type: string + - jsonPath: .spec.interfaces + name: Interfaces + type: string + - jsonPath: .spec.nodeSelectors + name: Node Selectors + priority: 10 + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: L2Advertisement allows to advertise the LoadBalancer IPs provided + by the selected pools via L2. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: L2AdvertisementSpec defines the desired state of L2Advertisement. + properties: + interfaces: + description: A list of interfaces to announce from. The LB IP will + be announced only from these interfaces. If the field is not set, + we advertise from all the interfaces on the host. + items: + type: string + type: array + ipAddressPoolSelectors: + description: A selector for the IPAddressPools which would get advertised + via this advertisement. If no IPAddressPool is selected by this + or by the list, the advertisement is applied to all the IPAddressPools. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + ipAddressPools: + description: The list of IPAddressPools to advertise via this advertisement, + selected by name. + items: + type: string + type: array + nodeSelectors: + description: NodeSelectors allows to limit the nodes to announce as + next hops for the LoadBalancer IP. When empty, all the nodes having are + announced as next hops. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: array + type: object + status: + description: L2AdvertisementStatus defines the observed state of L2Advertisement. + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app: metallb + name: controller + namespace: metallb-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app: metallb + name: speaker + namespace: metallb-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app: metallb + name: controller + namespace: metallb-system +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resourceNames: + - memberlist + resources: + - secrets + verbs: + - list +- apiGroups: + - apps + resourceNames: + - controller + resources: + - deployments + verbs: + - get +- apiGroups: + - metallb.io + resources: + - bgppeers + verbs: + - get + - list +- apiGroups: + - metallb.io + resources: + - addresspools + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - bfdprofiles + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - ipaddresspools + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - bgpadvertisements + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - l2advertisements + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - communities + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app: metallb + name: pod-lister + namespace: metallb-system +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - list +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - addresspools + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - bfdprofiles + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - bgppeers + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - l2advertisements + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - bgpadvertisements + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - ipaddresspools + verbs: + - get + - list + - watch +- apiGroups: + - metallb.io + resources: + - communities + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app: metallb + name: metallb-system:controller +rules: +- apiGroups: + - "" + resources: + - services + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - nodes + verbs: + - list +- apiGroups: + - "" + resources: + - services/status + verbs: + - update +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - policy + resourceNames: + - controller + resources: + - podsecuritypolicies + verbs: + - use +- apiGroups: + - admissionregistration.k8s.io + resourceNames: + - metallb-webhook-configuration + resources: + - validatingwebhookconfigurations + - mutatingwebhookconfigurations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + - mutatingwebhookconfigurations + verbs: + - list + - watch +- apiGroups: + - apiextensions.k8s.io + resourceNames: + - addresspools.metallb.io + - bfdprofiles.metallb.io + - bgpadvertisements.metallb.io + - bgppeers.metallb.io + - ipaddresspools.metallb.io + - l2advertisements.metallb.io + - communities.metallb.io + resources: + - customresourcedefinitions + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app: metallb + name: metallb-system:speaker +rules: +- apiGroups: + - "" + resources: + - services + - endpoints + - nodes + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - policy + resourceNames: + - speaker + resources: + - podsecuritypolicies + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app: metallb + name: controller + namespace: metallb-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: controller +subjects: +- kind: ServiceAccount + name: controller + namespace: metallb-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app: metallb + name: pod-lister + namespace: metallb-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pod-lister +subjects: +- kind: ServiceAccount + name: speaker + namespace: metallb-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: metallb + name: metallb-system:controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: metallb-system:controller +subjects: +- kind: ServiceAccount + name: controller + namespace: metallb-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app: metallb + name: metallb-system:speaker +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: metallb-system:speaker +subjects: +- kind: ServiceAccount + name: speaker + namespace: metallb-system +--- +apiVersion: v1 +data: + excludel2.yaml: | + announcedInterfacesToExclude: ["docker.*", "cbr.*", "dummy.*", "virbr.*", "lxcbr.*", "veth.*", "lo", "^cali.*", "^tunl.*", "flannel.*", "kube-ipvs.*", "cni.*", "^nodelocaldns.*"] +kind: ConfigMap +metadata: + name: metallb-excludel2 + namespace: metallb-system +--- +apiVersion: v1 +kind: Secret +metadata: + name: webhook-server-cert + namespace: metallb-system +--- +apiVersion: v1 +kind: Service +metadata: + name: webhook-service + namespace: metallb-system +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + component: controller +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: metallb + component: controller + name: controller + namespace: metallb-system +spec: + revisionHistoryLimit: 3 + selector: + matchLabels: + app: metallb + component: controller + template: + metadata: + annotations: + prometheus.io/port: "7472" + prometheus.io/scrape: "true" + labels: + app: metallb + component: controller + spec: + containers: + - args: + - --port=7472 + - --log-level=info + env: + - name: METALLB_ML_SECRET_NAME + value: memberlist + - name: METALLB_DEPLOYMENT + value: controller + image: quay.io/metallb/controller:v0.13.10 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /metrics + port: monitoring + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + name: controller + ports: + - containerPort: 7472 + name: monitoring + - containerPort: 9443 + name: webhook-server + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /metrics + port: monitoring + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - all + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + nodeSelector: + kubernetes.io/os: linux + securityContext: + fsGroup: 65534 + runAsNonRoot: true + runAsUser: 65534 + serviceAccountName: controller + terminationGracePeriodSeconds: 0 + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-cert +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + labels: + app: metallb + component: speaker + name: speaker + namespace: metallb-system +spec: + selector: + matchLabels: + app: metallb + component: speaker + template: + metadata: + annotations: + prometheus.io/port: "7472" + prometheus.io/scrape: "true" + labels: + app: metallb + component: speaker + spec: + containers: + - args: + - --port=7472 + - --log-level=info + env: + - name: METALLB_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: METALLB_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: METALLB_ML_BIND_ADDR + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: METALLB_ML_LABELS + value: app=metallb,component=speaker + - name: METALLB_ML_SECRET_KEY_PATH + value: /etc/ml_secret_key + image: quay.io/metallb/speaker:v0.13.10 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /metrics + port: monitoring + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + name: speaker + ports: + - containerPort: 7472 + name: monitoring + - containerPort: 7946 + name: memberlist-tcp + - containerPort: 7946 + name: memberlist-udp + protocol: UDP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /metrics + port: monitoring + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_RAW + drop: + - ALL + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /etc/ml_secret_key + name: memberlist + readOnly: true + - mountPath: /etc/metallb + name: metallb-excludel2 + readOnly: true + hostNetwork: true + nodeSelector: + kubernetes.io/os: linux + serviceAccountName: speaker + terminationGracePeriodSeconds: 2 + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + operator: Exists + volumes: + - name: memberlist + secret: + defaultMode: 420 + secretName: memberlist + - configMap: + defaultMode: 256 + name: metallb-excludel2 + name: metallb-excludel2 +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + creationTimestamp: null + name: metallb-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: metallb-system + path: /validate-metallb-io-v1beta2-bgppeer + failurePolicy: Fail + name: bgppeersvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta2 + operations: + - CREATE + - UPDATE + resources: + - bgppeers + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: metallb-system + path: /validate-metallb-io-v1beta1-addresspool + failurePolicy: Fail + name: addresspoolvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - addresspools + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: metallb-system + path: /validate-metallb-io-v1beta1-bfdprofile + failurePolicy: Fail + name: bfdprofilevalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - DELETE + resources: + - bfdprofiles + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: metallb-system + path: /validate-metallb-io-v1beta1-bgpadvertisement + failurePolicy: Fail + name: bgpadvertisementvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - bgpadvertisements + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: metallb-system + path: /validate-metallb-io-v1beta1-community + failurePolicy: Fail + name: communityvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - communities + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: metallb-system + path: /validate-metallb-io-v1beta1-ipaddresspool + failurePolicy: Fail + name: ipaddresspoolvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - ipaddresspools + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: metallb-system + path: /validate-metallb-io-v1beta1-l2advertisement + failurePolicy: Fail + name: l2advertisementvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - l2advertisements + sideEffects: None diff --git a/Ansible/playbooks/files/metallb.yaml b/Ansible/playbooks/files/metallb.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8169310a7df160ed6db40c0faafd9e26bb3c9037 --- /dev/null +++ b/Ansible/playbooks/files/metallb.yaml @@ -0,0 +1,16 @@ +# Layer 2 configuration +# <https://metallb.universe.tf/configuration/#layer-2-configuration> +apiVersion: metallb.io/v1beta1 +kind: IPAddressPool +metadata: + name: default + namespace: metallb-system +spec: + addresses: + - 172.18.0.1/24 # Adjust this range based on your Docker network +--- +apiVersion: metallb.io/v1beta1 +kind: L2Advertisement +metadata: + name: default + namespace: metallb-system diff --git a/Ansible/playbooks/kind-metallb.yml b/Ansible/playbooks/kind-metallb.yml new file mode 100644 index 0000000000000000000000000000000000000000..ed97d539c095cf1413af30cc23dea272095b97dd --- /dev/null +++ b/Ansible/playbooks/kind-metallb.yml @@ -0,0 +1 @@ +--- diff --git a/Application/backend/app.log b/Application/backend/app.log deleted file mode 100644 index 9cee2c841a0fc8ba39b7c0cb3cba513b8df98ec7..0000000000000000000000000000000000000000 --- a/Application/backend/app.log +++ /dev/null @@ -1,164 +0,0 @@ -2024-12-02 12:10:55,122 - __main__ - INFO - Starting Flask application... -2024-12-02 12:11:05,697 - __main__ - INFO - Starting Flask application... -2024-12-02 12:11:05,701 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m - * Running on all addresses (0.0.0.0) - * Running on http://127.0.0.1:8000 - * Running on http://192.168.1.93:8000 -2024-12-02 12:11:05,701 - werkzeug - INFO - [33mPress CTRL+C to quit[0m -2024-12-02 12:11:50,693 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:11:50] "OPTIONS /enroll HTTP/1.1" 200 - -2024-12-02 12:11:50,703 - __main__ - INFO - Enrollment attempt for email: test@gmail.com -2024-12-02 12:11:51,392 - __main__ - ERROR - Unexpected error: An error occurred (InvalidAccessKeyId) when calling the PutObject operation: Unknown -2024-12-02 12:11:51,396 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:11:51] "[35m[1mPOST /enroll HTTP/1.1[0m" 500 - -2024-12-02 12:19:27,242 - __main__ - INFO - Starting Flask application... -2024-12-02 12:19:27,246 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m - * Running on all addresses (0.0.0.0) - * Running on http://127.0.0.1:8000 - * Running on http://192.168.1.93:8000 -2024-12-02 12:19:27,246 - werkzeug - INFO - [33mPress CTRL+C to quit[0m -2024-12-02 12:19:42,112 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:19:42] "OPTIONS /enroll HTTP/1.1" 200 - -2024-12-02 12:19:42,115 - __main__ - INFO - Enrollment attempt for email: test@gmail.com -2024-12-02 12:19:42,700 - __main__ - ERROR - Unexpected error: An error occurred (InvalidAccessKeyId) when calling the PutObject operation: Unknown -2024-12-02 12:19:42,702 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:19:42] "[35m[1mPOST /enroll HTTP/1.1[0m" 500 - -2024-12-02 12:20:19,205 - __main__ - INFO - AWS_ACCESS_KEY_ID: AKIAVEKYIBTQEJB2XSNM -2024-12-02 12:20:19,205 - __main__ - INFO - AWS_SECRET_ACCESS_KEY: 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 -2024-12-02 12:20:19,205 - __main__ - INFO - AWS_ENDPOINT_URL: https://os.zhdk.cloud.switch.ch -2024-12-02 12:20:19,205 - __main__ - INFO - S3_BUCKET_NAME: cloud-bach-proj -2024-12-02 12:20:19,272 - __main__ - INFO - Starting Flask application... -2024-12-02 12:20:19,274 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m - * Running on all addresses (0.0.0.0) - * Running on http://127.0.0.1:8000 - * Running on http://192.168.1.93:8000 -2024-12-02 12:20:19,274 - werkzeug - INFO - [33mPress CTRL+C to quit[0m -2024-12-02 12:21:40,705 - __main__ - INFO - SWTICH_ACCESS_KEY_ID: None -2024-12-02 12:21:40,705 - __main__ - INFO - SWITCH_SECRET_ACCESS_KEY: None -2024-12-02 12:21:40,705 - __main__ - INFO - SWTICH_ENDPOINT_URL: None -2024-12-02 12:21:40,705 - __main__ - INFO - S3_BUCKET_NAME: cloud-bach-proj -2024-12-02 12:21:40,713 - botocore.credentials - INFO - Found credentials in environment variables. -2024-12-02 12:21:40,766 - botocore.configprovider - INFO - Found endpoint for s3 via: environment_global. -2024-12-02 12:21:40,770 - __main__ - INFO - Starting Flask application... -2024-12-02 12:21:40,773 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m - * Running on all addresses (0.0.0.0) - * Running on http://127.0.0.1:8000 - * Running on http://192.168.1.93:8000 -2024-12-02 12:21:40,773 - werkzeug - INFO - [33mPress CTRL+C to quit[0m -2024-12-02 12:21:51,332 - __main__ - INFO - SWTICH_ACCESS_KEY_ID: None -2024-12-02 12:21:51,332 - __main__ - INFO - SWITCH_SECRET_ACCESS_KEY: None -2024-12-02 12:21:51,332 - __main__ - INFO - SWTICH_ENDPOINT_URL: None -2024-12-02 12:21:51,332 - __main__ - INFO - S3_BUCKET_NAME: cloud-bach-proj -2024-12-02 12:21:51,340 - botocore.credentials - INFO - Found credentials in environment variables. -2024-12-02 12:21:51,389 - botocore.configprovider - INFO - Found endpoint for s3 via: environment_global. -2024-12-02 12:21:51,394 - __main__ - INFO - Starting Flask application... -2024-12-02 12:21:51,396 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m - * Running on all addresses (0.0.0.0) - * Running on http://127.0.0.1:8000 - * Running on http://192.168.1.93:8000 -2024-12-02 12:21:51,396 - werkzeug - INFO - [33mPress CTRL+C to quit[0m -2024-12-02 12:23:04,117 - __main__ - INFO - SWTICH_ACCESS_KEY_ID: None -2024-12-02 12:23:04,117 - __main__ - INFO - SWITCH_SECRET_ACCESS_KEY: None -2024-12-02 12:23:04,117 - __main__ - INFO - SWTICH_ENDPOINT_URL: None -2024-12-02 12:23:04,117 - __main__ - INFO - S3_BUCKET_NAME: None -2024-12-02 12:23:04,126 - botocore.credentials - INFO - Found credentials in environment variables. -2024-12-02 12:23:04,196 - __main__ - CRITICAL - S3_BUCKET_NAME environment variable is not set -2024-12-02 12:53:11,151 - __main__ - INFO - SWTICH_ACCESS_KEY_ID: 4406dbe746a24614a9bc8f7ec864e59f -2024-12-02 12:53:11,151 - __main__ - INFO - SWITCH_SECRET_ACCESS_KEY: cec6e60954b24a51923fe5aaea9fbb3b -2024-12-02 12:53:11,151 - __main__ - INFO - SWTICH_ENDPOINT_URL: https://os.zhdk.cloud.switch.ch -2024-12-02 12:53:11,151 - __main__ - INFO - S3_BUCKET_NAME: cloud-bach-proj -2024-12-02 12:53:11,385 - __main__ - INFO - Starting Flask application... -2024-12-02 12:53:11,391 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m - * Running on all addresses (0.0.0.0) - * Running on http://127.0.0.1:8000 - * Running on http://192.168.1.93:8000 -2024-12-02 12:53:11,391 - werkzeug - INFO - [33mPress CTRL+C to quit[0m -2024-12-02 12:53:19,651 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:53:19] "OPTIONS /enroll HTTP/1.1" 200 - -2024-12-02 12:53:19,656 - __main__ - INFO - Enrollment attempt for email: test@gmail.com -2024-12-02 12:53:20,645 - __main__ - ERROR - Unexpected error: An error occurred (NoSuchBucket) when calling the PutObject operation: Unknown -2024-12-02 12:53:20,647 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:53:20] "[35m[1mPOST /enroll HTTP/1.1[0m" 500 - -2024-12-02 12:54:00,835 - __main__ - INFO - SWTICH_ACCESS_KEY_ID: 4406dbe746a24614a9bc8f7ec864e59f -2024-12-02 12:54:00,835 - __main__ - INFO - SWITCH_SECRET_ACCESS_KEY: cec6e60954b24a51923fe5aaea9fbb3b -2024-12-02 12:54:00,835 - __main__ - INFO - SWTICH_ENDPOINT_URL: https://os.zhdk.cloud.switch.ch -2024-12-02 12:54:00,835 - __main__ - INFO - S3_BUCKET_NAME: cloud-bach-proj -2024-12-02 12:54:00,923 - __main__ - INFO - Starting Flask application... -2024-12-02 12:54:01,360 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m - * Running on all addresses (0.0.0.0) - * Running on http://127.0.0.1:8000 - * Running on http://192.168.1.93:8000 -2024-12-02 12:54:01,361 - werkzeug - INFO - [33mPress CTRL+C to quit[0m -2024-12-02 12:54:09,932 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:54:09] "OPTIONS /enroll HTTP/1.1" 200 - -2024-12-02 12:54:09,937 - __main__ - INFO - Enrollment attempt for email: test@gmail.com -2024-12-02 12:54:10,203 - __main__ - INFO - Successfully enrolled user: test@gmail.com -2024-12-02 12:54:10,205 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:54:10] "POST /enroll HTTP/1.1" 200 - -2024-12-02 12:54:19,954 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:54:19] "OPTIONS /login HTTP/1.1" 200 - -2024-12-02 12:54:19,960 - __main__ - INFO - Login attempt for email: test@gmail.com -2024-12-02 12:54:20,282 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:54:20] "POST /login HTTP/1.1" 200 - -2024-12-02 12:54:27,064 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:54:27] "OPTIONS /logout HTTP/1.1" 200 - -2024-12-02 12:54:27,069 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:54:27] "[31m[1mPOST /logout HTTP/1.1[0m" 400 - -2024-12-02 12:55:40,966 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:55:40] "OPTIONS /logout HTTP/1.1" 200 - -2024-12-02 12:55:40,971 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:55:40] "[31m[1mPOST /logout HTTP/1.1[0m" 400 - -2024-12-02 12:55:46,985 - __main__ - INFO - SWTICH_ACCESS_KEY_ID: 4406dbe746a24614a9bc8f7ec864e59f -2024-12-02 12:55:46,985 - __main__ - INFO - SWITCH_SECRET_ACCESS_KEY: cec6e60954b24a51923fe5aaea9fbb3b -2024-12-02 12:55:46,985 - __main__ - INFO - SWTICH_ENDPOINT_URL: https://os.zhdk.cloud.switch.ch -2024-12-02 12:55:46,985 - __main__ - INFO - S3_BUCKET_NAME: cloud-bach-proj -2024-12-02 12:55:47,082 - __main__ - INFO - Starting Flask application... -2024-12-02 12:55:47,580 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m - * Running on all addresses (0.0.0.0) - * Running on http://127.0.0.1:8000 - * Running on http://192.168.1.93:8000 -2024-12-02 12:55:47,580 - werkzeug - INFO - [33mPress CTRL+C to quit[0m -2024-12-02 12:55:53,216 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:55:53] "OPTIONS /login HTTP/1.1" 200 - -2024-12-02 12:55:53,221 - __main__ - INFO - Login attempt for email: test@gmail.com -2024-12-02 12:55:53,396 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:55:53] "POST /login HTTP/1.1" 200 - -2024-12-02 12:55:54,335 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:55:54] "OPTIONS /logout HTTP/1.1" 200 - -2024-12-02 12:55:54,340 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:55:54] "[31m[1mPOST /logout HTTP/1.1[0m" 400 - -2024-12-02 12:56:23,774 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:56:23] "OPTIONS /logout HTTP/1.1" 200 - -2024-12-02 12:56:23,780 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:56:23] "[31m[1mPOST /logout HTTP/1.1[0m" 400 - -2024-12-02 12:56:30,635 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:56:30] "OPTIONS /login HTTP/1.1" 200 - -2024-12-02 12:56:30,641 - __main__ - INFO - Login attempt for email: test@gmail.com -2024-12-02 12:56:31,075 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:56:31] "POST /login HTTP/1.1" 200 - -2024-12-02 12:56:32,425 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:56:32] "OPTIONS /logout HTTP/1.1" 200 - -2024-12-02 12:56:32,430 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:56:32] "[31m[1mPOST /logout HTTP/1.1[0m" 400 - -2024-12-02 12:57:02,178 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:57:02] "OPTIONS /login HTTP/1.1" 200 - -2024-12-02 12:57:02,184 - __main__ - INFO - Login attempt for email: test@gmail.com -2024-12-02 12:57:02,825 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:57:02] "POST /login HTTP/1.1" 200 - -2024-12-02 12:57:04,463 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:57:04] "OPTIONS /logout HTTP/1.1" 200 - -2024-12-02 12:57:05,167 - werkzeug - INFO - 127.0.0.1 - - [02/Dec/2024 12:57:05] "POST /logout HTTP/1.1" 200 - -2024-12-09 09:10:26,299 - __main__ - INFO - SWTICH_ACCESS_KEY_ID: 4406dbe746a24614a9bc8f7ec864e59f -2024-12-09 09:10:26,299 - __main__ - INFO - SWITCH_SECRET_ACCESS_KEY: cec6e60954b24a51923fe5aaea9fbb3b -2024-12-09 09:10:26,299 - __main__ - INFO - SWTICH_ENDPOINT_URL: https://os.zhdk.cloud.switch.ch -2024-12-09 09:10:26,299 - __main__ - INFO - S3_BUCKET_NAME: cloud-bach-proj -2024-12-09 09:10:26,615 - __main__ - INFO - Starting Flask application... -2024-12-09 09:10:27,453 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m - * Running on all addresses (0.0.0.0) - * Running on http://127.0.0.1:8000 - * Running on http://192.168.1.159:8000 -2024-12-09 09:10:27,453 - werkzeug - INFO - [33mPress CTRL+C to quit[0m -2024-12-09 09:20:42,041 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:20:42] "OPTIONS /enroll HTTP/1.1" 200 - -2024-12-09 09:20:42,045 - __main__ - INFO - Enrollment attempt for email: sapos@hotmail.com -2024-12-09 09:20:43,477 - __main__ - INFO - Successfully enrolled user: sapos@hotmail.com -2024-12-09 09:20:43,478 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:20:43] "POST /enroll HTTP/1.1" 200 - -2024-12-09 09:20:52,022 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:20:52] "OPTIONS /login HTTP/1.1" 200 - -2024-12-09 09:20:52,026 - __main__ - INFO - Login attempt for email: sapos@hotmail.com -2024-12-09 09:20:52,208 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:20:52] "[31m[1mPOST /login HTTP/1.1[0m" 401 - -2024-12-09 09:20:56,219 - __main__ - INFO - Login attempt for email: sapos@hotmail.com -2024-12-09 09:20:56,909 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:20:56] "POST /login HTTP/1.1" 200 - -2024-12-09 09:21:21,262 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:21] "OPTIONS /logout HTTP/1.1" 200 - -2024-12-09 09:21:21,692 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:21] "POST /logout HTTP/1.1" 200 - -2024-12-09 09:21:29,789 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:29] "OPTIONS /enroll HTTP/1.1" 200 - -2024-12-09 09:21:29,793 - __main__ - INFO - Enrollment attempt for email: fran.abm94@gmail.com -2024-12-09 09:21:30,036 - __main__ - INFO - Successfully enrolled user: fran.abm94@gmail.com -2024-12-09 09:21:30,037 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:30] "POST /enroll HTTP/1.1" 200 - -2024-12-09 09:21:54,239 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:54] "OPTIONS /login HTTP/1.1" 200 - -2024-12-09 09:21:54,242 - __main__ - INFO - Login attempt for email: fran.abm94@gmail.com -2024-12-09 09:21:54,689 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:54] "POST /login HTTP/1.1" 200 - -2024-12-09 09:21:56,036 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:56] "OPTIONS /logout HTTP/1.1" 200 - -2024-12-09 09:21:56,455 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:56] "POST /logout HTTP/1.1" 200 - -2024-12-09 09:21:58,042 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:58] "OPTIONS /enroll HTTP/1.1" 200 - -2024-12-09 09:21:58,044 - __main__ - INFO - Enrollment attempt for email: fran.abm94@gmail.com -2024-12-09 09:21:58,125 - __main__ - INFO - Enrollment failed - user already exists: fran.abm94@gmail.com -2024-12-09 09:21:58,126 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:21:58] "[31m[1mPOST /enroll HTTP/1.1[0m" 409 - -2024-12-09 09:22:05,692 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:22:05] "OPTIONS /enroll HTTP/1.1" 200 - -2024-12-09 09:22:05,694 - __main__ - INFO - Enrollment attempt for email: fran.abm@gmail.com -2024-12-09 09:22:06,199 - __main__ - INFO - Successfully enrolled user: fran.abm@gmail.com -2024-12-09 09:22:06,200 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:22:06] "POST /enroll HTTP/1.1" 200 - -2024-12-09 09:22:16,204 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:22:16] "OPTIONS /login HTTP/1.1" 200 - -2024-12-09 09:22:16,205 - __main__ - INFO - Login attempt for email: fran.abm@gmail.com -2024-12-09 09:22:16,590 - werkzeug - INFO - 127.0.0.1 - - [09/Dec/2024 09:22:16] "POST /login HTTP/1.1" 200 - diff --git a/README.md b/README.md index 057e6944755161b5fa9b9be36374ee567e82f178..439c7ab2f43a0377608132077350d4fec78da41d 100644 --- a/README.md +++ b/README.md @@ -20,47 +20,77 @@ S3 storage for the enrollment and session data. ## Architecture -The system architecture is composed of 3 tiers: - 1. The **front-end** that provides a log-in Web GUI (languages: HTML5, JS) - and sends incoming authentication requests to the back-end. - 2. The **back-end** (languages: Python/Flask) that receives - and handles authentication requests from the front-end. All the session - logic is implemented here in a CRUD-like fashion: session objects are - stored in an S3-compatible storage. +The system's 3-tier architecture is microservice-based: + + 1. The replicated **front-end** tier implements: + * a login Web GUI composed of several *views* (languages: HTML5, JS) and + * associated logic (languages: Python/Flask) which sends incoming + authentication requests to the back-end and returns the results to the + views. The ingress/egress point is a load balancer that exposes an + external IP address. + 2. The **back-end** tier (languages: Python/Flask) tier receives and handles + authentication requests from the front-end. All the enrollment and + session logic is implemented here in a CRUD-like fashion: corresponding + objects are stored in an S3-compatible storage. 3. The **storage** tier is a standard S3-like object storage which can be accessed only by the back-end. -:construction: **TO-DO**: add API diagrams: components, activity. + +*Application's architecture and deployment schema* + + +### Infrastructure and deployment + +The front-end replicas and the back-end are deployed in separate containers +hosted by a Kubernetes-based MetalLB service deployment. The service, on its +turn, is hosted by a 2-node KinD cluster installed on a single VM +infrastructure. ### Front-end -:construction: Web portal with REST-based functions, written in HTML5 -and JavaScript. The service routes are: +Web portal with REST-based functions, written in HTML5, JavaScript (views) and +Python/Flask (main logic). All related files are in directory `frontend/`. - * `enroll`: subscribe to the system with credentials - * `unenroll`: delete subscription credentials +The REST service *routes* are: + + * `enroll`: sign-up (subscribe) to the system with credentials + * `unenroll`: delete subscription credentials (remove account) * `login`: authenticate with e-mail and, if needed (first login), password * `logout`: de-authenticate by removing the current session -:construction: **TO-DO**: add API prototypes. +The following files in directory `views/` handle the client-side workflow. + + * `index.html` provides just two buttons: + * "Login" linked to the view `login.html` + * "Sign up" (enroll) linked to the view `signup.html` + * `signup.html` provides a form with with input fields "e-mail" and + "password" and is linked to the `dashboard.html` view + * `login.html` provides a form with input fields "e-mail" and "password" and + is linked to the `dashboard.html` view. + * `dashboard.html` provides two buttons "Logout" and "Remove account" (unenroll) -Input fields: *e-mail* and *password*. +The file `main.py` handles the REST logic by conveying all requests to the +back-end. -Buttons: 4, named as the routes above. +:bulb: **This part does not requires adaptations.** ### Back-end -:construction: Session management subsystem written in Python/Flask +The single file `backend/main.py` (Python/Flask) implements the enrollment and +session management logic by handling REST requests coming from the +front-end. The corresponding objects are managed in a CRUD-like fashion +in/from a single S3 storage bucket. -:tools: This part requires some development by the students. +:tools: **This part requires some development.** See the details in the +boilerplate `backend/main.py`. ### Storage -:construction: S3-like object storage composed of 1 buckets with two directories: one for -*enrollment* data, one for *session* data. +This is a single S3-like buckets with two directories: one for *enrollment* +data, one for *session* data. Objects shall be written as JSON data based on the following proposed schema. @@ -139,6 +169,7 @@ Minimum schema (you're free to extend it): Example data for object named `foo@bar.com`: ``` json { + "client": "192.168.1.2", "timestamp": 1733330967 } ``` @@ -169,10 +200,10 @@ nothing else is recorded by the back-end. #### Enroll -A new user subscribes to the system via the `enroll` function: +A *new* user subscribes to the system via the `enroll` function: 1. **User** provides enrollment data (*e-mail* and *password*) via the the - front-end. + front-end's `signup` view. 2. **Front-end** sends enrollment data to the back-end. 3. **Back-end** verifies enrollment data: - IF user exists THEN returns 'KO:ALREADY_ENROLLED' @@ -184,24 +215,26 @@ A new user subscribes to the system via the `enroll` function: #### Unenroll -An enrolled unsubscribes from the system with the `unenroll` function: +An *enrolled* user unsubscribes from the system (removes their account) with +the `unenroll` function: - 1. **User** provides enrollment data (*e-mail* and *password*) via the the - front-end. + 1. **User** provides enrollment *e-mail* via the the front-end's `dashboard` + view. 2. **Front-end** sends enrollment data to the back-end. 3. **Back-end** verifies enrollment data: - IF user does not exists THEN returns 'KO:NO\_SUCH\_USER' - ELSE 1. Removes enrollment data and any active sessions from the storage 2. Returns 'OK:UNENROLLED' to the front-end - 4. **Front-end** receives response from the back-end and shows it to the user. + 4. **Front-end** receives response from the back-end and shows it to the + user. #### Login An enrolled user authenticates to the system with the `login` function: - 1. **User** provides *e-mail* via the the front-end. + 1. **User** provides *e-mail* via the the front-end's view `login`. 2. **Front-end** sends *e-mail* to the back-end. 3. **Back-end** verifies the *e-mail*: - IF user does not exists THEN returns 'KO:NO\_SUCH\_USER' @@ -227,7 +260,7 @@ An enrolled user authenticates to the system with the `login` function: An enrolled user deauthenticates to the system with the `logout` function: - 1. **User** provides *e-mail* via the the front-end. + 1. **User** provides *e-mail* via the the front-end's view `dashboard`. 2. **Front-end** sends *e-mail* to the back-end. 3. **Back-end** verifies the *e-mail*: - IF user does not exists THEN returns 'KO:NO\_SUCH\_USER' @@ -247,7 +280,7 @@ is composed of * A single VM featuring: * Source image: A Debian 12 Bookworm * Flavor: 2 vCPUs, 4GB RAM, 40GB root disk -- no extra volume needed - * A KinD installation + * A KinD/Kubectl installation * One S3 bucket. The infrastructure (computing instance + S3 storage) shall be provisioned via @@ -255,52 +288,86 @@ The infrastructure (computing instance + S3 storage) shall be provisioned via :bulb: References: * Terraform: https://registry.terraform.io/providers/hashicorp/aws/latest/docs - * :question: what else? ## Service deployment -The service is deployed on a 2-pods microservice hosted by a two-node KinD -cluster, with a single MetalLB load-balancer entry point, as done with the +The service shall be deployed on a 3-pods K8s microservice hosted by a +two-node KinD cluster, with a single MetalLB load-balancer entry point, as +done with the [Lab-K8s](https://gitedu.hesge.ch/lsds/teaching/bachelor/cloud-and-deployment/lab-k8s). +The front-end shall be replicated over 2 pods. The 3rd pod shall host the +back-end. The whole software stack, apart from the KinD package, shall be deployed via -**Ansible**. Of course, instead of the dummy `http-echo` app, a different -Docker image shall be used -- :construction: see the [project's Docker file -boilerplate](provide-link-please). This image shall be rebuilt after any -modification to the application code. The application shall be redeployed -whenever its image is updated. +**Ansible**. Of course, instead of the dummy `http-echo` app, two different +Docker images shall be used -- :construction: see the [project's Docker file +boilerplate](provide-link-please): one for the front-end, the other for the +back-end, both hosted in the [Docker Hub registry](https://hub.docker.com/) -- +you shall create a personal public repository. **We trust you, please, do not +cheat!** + +The front-end image does not need to be rebuilt, unless you want to implement +some client-side (HTML/JS) bonuses. + +The back-end image shall be rebuilt after any modification to the application +code. + +The whole stack shall be redeployed whenever any of its images are updated. ## Tasks :construction: **To be finalized** +:warning: Please respect the file layout provided by this repository! + You shall: -0. Fork this repository. -1. Complete the Python back-end file(s) in folder `Application/back-end.py`. -2. Rebuild the application Docker image, and store it (somewhere) -- - **(:question: TO-DO - We should provide instructions + Dockerfile: - - Build image on the student's workstation - - What's better: push to Dockerhub vs to scp to VM + import? - )**. This task shall be automated via Ansible -- see below. -3. Complete your Terraform files from the version you developed in +1. Fork this repository. +2. Complete the Python back-end file(s) in folder + `Application/backend/main.py`. +3. Rebuild the application back-end Docker image, and push it to your public + Docker Hub repositry -- **(:question: TO-DO - We should provide + instructions)**. This task shall be automated via Ansible -- see below. +4. Complete your Terraform files from the version you developed in [Lab-Terraform](https://gitedu.hesge.ch/lsds/teaching/bachelor/cloud-and-deployment/lab-terraform/-/blob/main/SwitchEngines/README.md) up to Task #8. Your recipe shall handle only the provisioning of the VM plus an S3 storage bucket -- no KinD/Kubectl package installation. Commit - your recipe files (included Cloud-init) and in directory `Terraform/`. -4. Complete your Ansible playbook, starting from the version you developed in + your recipe files (included Cloud-init) and in directory `Terraform/`. +5. Complete your Ansible playbook, starting from the version you developed in [Lab-Ansible](https://gitedu.hesge.ch/lsds/teaching/bachelor/cloud-and-deployment/lab-ansible) - Task #10, to: - - expose the application portal IP (e.g., load-balancer IP) to the + Task #10, to (commit all realted files in directory `Ansible/`): + - expose the application portal's IP (i.e, the load-balancer's) to the Internet via `socat` or other mechanism of your choice; - - :question: **(TO-DO: What's better? Local or registry [Docker])?** - rebuild and transfer/download the application image to your VM instance. - Commit these files in directory `Ansible/`. + - rebuild and push the application images to your Docker Hub + repository. These shall be [`local_action` + tasks.](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_delegation.html) + +:bulb: References: + * Build and push Docker images: https://docs.docker.com/get-started/introduction/build-and-push-first-image/ + * Ansible playbook delegation: + https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_delegation.html + + +### Bonuses + +You will get bonus for any of the following improvements. + + * Ask for the password when removing an account (unenroll) -- extra + safety. +0.2 points. + * Use password hashing in the back-end -- extra security. +0.1 points. + * Handle session expiration after a configurable amount of time (in + minutes). You can use an extra enrollment view's parameter + `expiration_time`. +0.3 points. + * Handle multiple sessions started from different browsers, e.g., private + navigation tab/window. +0.4 points. + * Support temporary disconnection via client session data stored in a Web + cookie (without the password) -- this requires some sort of [cryptographic + "nonce"](https://en.wikipedia.org/wiki/Cryptographic_nonce). +0.5 points. -### Tests +### Testing The following tests shall be passed by your implementation: diff --git a/Terraform/conf/cloud-init.packages.yaml b/Terraform/conf/cloud-init.packages.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3caed8137c5ce7139e91dd788f2fa206ea29aea0 --- /dev/null +++ b/Terraform/conf/cloud-init.packages.yaml @@ -0,0 +1,20 @@ +#cloud-config +--- + +# package_update: true +# package_upgrade: true + +groups: + - docker + +system_info: + default_user: + groups: [docker] + +# add any basic packages here: +packages: + - curl + - nano + - ripgrep + - docker.io + - bash-completion diff --git a/Terraform/conf/cloud-init.users.yaml b/Terraform/conf/cloud-init.users.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b675f4098514f5d4c57585c1e95b29083ce38020 --- /dev/null +++ b/Terraform/conf/cloud-init.users.yaml @@ -0,0 +1,15 @@ +#cloud-config +--- +groups: + - terraform + +system_info: + default_user: + name: terraform + gecos: terraform + primary_group: terraform + groups: [users, admin, sudo] + shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + ssh_authorized_keys: + - <your-ssh-ed25519-or-RSA-public-key> diff --git a/Terraform/main.tf b/Terraform/main.tf new file mode 100644 index 0000000000000000000000000000000000000000..20bacf6fbbbed311d6c0c8ccd930c82ce0223741 --- /dev/null +++ b/Terraform/main.tf @@ -0,0 +1 @@ +# main.tf diff --git a/Terraform/outputs.tf b/Terraform/outputs.tf new file mode 100644 index 0000000000000000000000000000000000000000..237252c761f173f3ed90534c1afd40bf30bee3bd --- /dev/null +++ b/Terraform/outputs.tf @@ -0,0 +1 @@ +# outputs.tf diff --git a/Terraform/variables.tf b/Terraform/variables.tf new file mode 100644 index 0000000000000000000000000000000000000000..57bf62f7a78dc418a07075d6ceb1e598bd20b883 --- /dev/null +++ b/Terraform/variables.tf @@ -0,0 +1 @@ +# variables.tf diff --git a/app_arch_depl.png b/app_arch_depl.png new file mode 100644 index 0000000000000000000000000000000000000000..422710ea26038ceb87e88f4eb4a97b102bba2863 Binary files /dev/null and b/app_arch_depl.png differ