From 98d32642cddce71efc30bf743c2e1baed7e7bc7f Mon Sep 17 00:00:00 2001 From: "noussair.hamrit" Date: Mon, 16 Jun 2025 16:29:39 +0200 Subject: [PATCH] =?UTF-8?q?Initial=20commit=20-=20update=20else=20conditio?= =?UTF-8?q?n=20on=20the=20line=20239=20in=20templates/Deployment=20-=20upd?= =?UTF-8?q?ate=20=20st-common=20version=20from=200.1.10=20to=200.1.12=20on?= =?UTF-8?q?=20Chart.yaml=20file=20-=20add=20gitlab=20ci/cd=20pipeline=20to?= =?UTF-8?q?=20=20package=20the=20Helm=20chart=20into=20a=20.tgz.=20and=20P?= =?UTF-8?q?ublish=20it=20to=20GitLab=E2=80=99s=20Helm=20package=20registry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 40 + Chart.lock | 9 + Chart.yaml | 34 + README.md | 325 ++++++ archive/coa-master | 55 + archive/tls-master | 247 +++++ charts/mariadb-20.5.9.tgz | Bin 0 -> 77309 bytes charts/st-common-0.1.12.tgz | Bin 0 -> 23576 bytes files/docker-entrypoint-initdb.d/README.md | 3 + files/mods-available/sql | 366 +++++++ files/schema/mysql.sql | 165 +++ files/sites-available/coa | 41 + files/sites-available/default | 1072 ++++++++++++++++++++ files/sites-available/dhcp | 595 +++++++++++ files/sites-available/inner-tunnel | 126 +++ files/sites-available/status | 126 +++ files/sites-available/tls | 603 +++++++++++ index.yaml | 115 +++ packages/freeradius-1.0.3.tgz | Bin 0 -> 158980 bytes templates/Certificate.yaml | 54 + templates/ConfigMap/clients.yaml | 23 + templates/ConfigMap/envvars.yaml | 75 ++ templates/ConfigMap/mods-enabled.yaml | 21 + templates/ConfigMap/sites-enabled.yaml | 29 + templates/Deployment.yaml | 366 +++++++ templates/Istio/Gateway.yaml | 69 ++ templates/Istio/VirtualService.yaml | 47 + templates/NetworkPolicy.yaml | 57 ++ templates/PersistentVolumeClaim.yaml | 38 + templates/PodDisruptionBudget.yaml | 28 + templates/PrometheusRule.yaml | 25 + templates/Role.yaml | 29 + templates/RoleBinding.yaml | 26 + templates/Secret/credentials.yaml | 38 + templates/Secret/sql-tls.yaml | 30 + templates/Secret/tls.yaml | 30 + templates/Service.yaml | 98 ++ templates/ServiceAccount.yaml | 27 + templates/_helpers/_databases.tpl | 95 ++ templates/_helpers/_helpers.tpl | 140 +++ templates/_helpers/_images.tpl | 14 + templates/_helpers/_names.tpl | 10 + templates/_helpers/_volumes.tpl | 18 + values-test.yaml | 44 + values.yaml | 985 ++++++++++++++++++ 45 files changed, 6338 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 Chart.lock create mode 100644 Chart.yaml create mode 100644 README.md create mode 100644 archive/coa-master create mode 100644 archive/tls-master create mode 100644 charts/mariadb-20.5.9.tgz create mode 100644 charts/st-common-0.1.12.tgz create mode 100644 files/docker-entrypoint-initdb.d/README.md create mode 100644 files/mods-available/sql create mode 100644 files/schema/mysql.sql create mode 100644 files/sites-available/coa create mode 100644 files/sites-available/default create mode 100644 files/sites-available/dhcp create mode 100644 files/sites-available/inner-tunnel create mode 100644 files/sites-available/status create mode 100644 files/sites-available/tls create mode 100644 index.yaml create mode 100644 packages/freeradius-1.0.3.tgz create mode 100644 templates/Certificate.yaml create mode 100644 templates/ConfigMap/clients.yaml create mode 100644 templates/ConfigMap/envvars.yaml create mode 100644 templates/ConfigMap/mods-enabled.yaml create mode 100644 templates/ConfigMap/sites-enabled.yaml create mode 100644 templates/Deployment.yaml create mode 100644 templates/Istio/Gateway.yaml create mode 100644 templates/Istio/VirtualService.yaml create mode 100644 templates/NetworkPolicy.yaml create mode 100644 templates/PersistentVolumeClaim.yaml create mode 100644 templates/PodDisruptionBudget.yaml create mode 100644 templates/PrometheusRule.yaml create mode 100644 templates/Role.yaml create mode 100644 templates/RoleBinding.yaml create mode 100644 templates/Secret/credentials.yaml create mode 100644 templates/Secret/sql-tls.yaml create mode 100644 templates/Secret/tls.yaml create mode 100644 templates/Service.yaml create mode 100644 templates/ServiceAccount.yaml create mode 100644 templates/_helpers/_databases.tpl create mode 100644 templates/_helpers/_helpers.tpl create mode 100644 templates/_helpers/_images.tpl create mode 100644 templates/_helpers/_names.tpl create mode 100644 templates/_helpers/_volumes.tpl create mode 100644 values-test.yaml create mode 100644 values.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..ee96660 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,40 @@ +default: + tags: + - docker-test + +stages: + - package + - publish + +variables: + CHART_NAME: "freeradius" + CHART_VERSION: "1.0.3" + PACKAGE_PATH: "packages" + HELM_EXPERIMENTAL_OCI: "1" + +package_chart: + stage: package + image: + name: alpine/helm:3.14.0 + entrypoint: [""] + script: + - helm repo add startechnica https://startechnica.github.io/apps + - helm dependency build . + - mkdir -p $PACKAGE_PATH + - helm package . --destination $PACKAGE_PATH + artifacts: + paths: + - ${PACKAGE_PATH}/${CHART_NAME}-${CHART_VERSION}.tgz + + +publish_chart: + stage: publish + image: alpine/curl:8.14.1 + script: + - | + curl --fail-with-body --request POST \ + --user gitlab-ci-token:$CI_JOB_TOKEN \ + --form "chart=@${PACKAGE_PATH}/${CHART_NAME}-${CHART_VERSION}.tgz" \ + "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/api/stable/charts" + only: + - main \ No newline at end of file diff --git a/Chart.lock b/Chart.lock new file mode 100644 index 0000000..57da691 --- /dev/null +++ b/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: st-common + repository: https://startechnica.github.io/apps + version: 0.1.12 +- name: mariadb + repository: oci://registry-1.docker.io/bitnamicharts + version: 20.5.9 +digest: sha256:03a311ace58596d28267595eab6c85c5d39af13a5864dbe04be8931a2262b6c7 +generated: "2025-06-16T16:20:04.252816273+02:00" diff --git a/Chart.yaml b/Chart.yaml new file mode 100644 index 0000000..50572a4 --- /dev/null +++ b/Chart.yaml @@ -0,0 +1,34 @@ +annotations: + category: AccessManagement +apiVersion: v2 +appVersion: 3.2.7 +dependencies: +- name: st-common + repository: https://startechnica.github.io/apps + version: 0.1.12 +- condition: mariadb.enabled + name: mariadb + repository: oci://registry-1.docker.io/bitnamicharts + version: 20.x.x +description: FreeRADIUS is a modular, high performance free RADIUS suite developed + and distributed under the GNU General Public License, version 2, and is free for + download and use. +home: https://github.com/startechnica/apps/tree/main/charts/freeradius +icon: https://freeradius.org/img/wordmark.svg +keywords: +- freeradius +- radius +- mysql +- postgresql +- ldap +kubeVersion: '>=1.24.0-0' +maintainers: +- email: firmansyah@nainggolan.id + name: firmansyahn + url: https://firmansyah.nainggolan.id +name: freeradius +sources: +- https://freeradius.org/ +- https://github.com/FreeRADIUS/freeradius-server +type: application +version: 1.0.3 diff --git a/README.md b/README.md new file mode 100644 index 0000000..1bcf2ae --- /dev/null +++ b/README.md @@ -0,0 +1,325 @@ + + +# Helm chart for FreeRADIUS + +FreeRADIUS is a modular, high performance free RADIUS suite developed and distributed under the GNU General Public License, version 2, and is free for download and use. + +[Overview of FreeRADIUS](https://freeradius.org/) + +**This chart is not maintained by the upstream project and any issues with the chart should be raised [here](https://github.com/startechnica/apps/issues/new/choose)** + +## TL;DR + +```console +helm repo add startechnica https://startechnica.github.io/apps +helm install my-release startechnica/freeradius +``` + +## Prerequisites + +- Kubernetes 1.22+ +- Helm 3.10.0+ + +## Installing the Chart + +To install the chart with the release name `my-release` on `my-release` namespace: + +```console +helm repo add startechnica https://startechnica.github.io/apps +helm install my-release startechnica/freeradius --namespace my-release --create-namespace +``` + +These commands deploy FreeRADIUS on the Kubernetes cluster in the default configuration. + +> **Tip**: List all releases using `helm list -A` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +helm delete my-release --namespace my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Parameters + +### Global parameters + +| Name | Description | Value | +| ------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----- | +| `global.imageRegistry` | Global Docker image registry | `""` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` | +| `global.storageClass` | Global StorageClass for Persistent Volume(s) | `""` | +| `global.namespaceOverride` | Override the namespace for resource deployed by the chart, but can itself be overridden by the local namespaceOverride | `""` | + + +### Common parameters + +| Name | Description | Value | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------- | +| `kubeVersion` | Force target Kubernetes version (using Helm capabilities if not set) | `""` | +| `nameOverride` | String to partially override common.names.fullname template with a string (will prepend the release name) | `""` | +| `namespaceOverride` | String to fully override common.names.namespace | `""` | +| `fullnameOverride` | String to fully override common.names.fullname template with a string | `""` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `schedulerName` | Name of the Kubernetes scheduler (other than default) | `""` | +| `clusterDomain` | Kubernetes DNS Domain name to use | `cluster.local` | +| `extraDeploy` | Array of extra objects to deploy with the release (evaluated as a template) | `[]` | +| `diagnosticMode.enabled` | Enable diagnostic mode (all probes will be disabled and the command will be overridden) | `false` | +| `diagnosticMode.command` | Command to override all containers in the deployment | `[]` | +| `diagnosticMode.args` | Args to override all containers in the deployment | `[]` | + + +### FreeRADIUS parameters + +| Name | Description | Value | +| ----------------------------------------------| -------------------------------------------------------------------------------------------------------------------------| -------------------------------| +| `image.registry` | FreeRADIUS image registry | `docker.io` | +| `image.repository` | FreeRADIUS image repository | `freeradius/freeradius-server` | +| `image.tag` | FreeRADIUS image tag (immutable tags are recommended) | `3.2.3` | +| `image.pullPolicy` | FreeRADIUS image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` | +| `image.debug` | Set to true if you would like to see extra information on logs | `false` | +| `hostAliases` | Deployment pod host aliases | `[]` | +| `command` | Override default container command (useful when using custom images) | `[]` | +| `args` | Override default container args (useful when using custom images) | `[]` | +| `extraEnvVars` | Extra environment variables to be set on FreeRADIUS containers | `[]` | +| `extraEnvVarsCM` | ConfigMap with extra environment variables | `""` | +| `extraEnvVarsSecret` | Secret with extra environment variables | `""` | +| `service.type` | Kubernetes service type | `ClusterIP` | +| `service.clusterIP` | Specific cluster IP when service type is cluster IP. Use `None` for headless service | `""` | +| `service.ports.auth` | FreeRADIUS Authentication and Authorization service port | `1812` | +| `service.ports.acct` | FreeRADIUS Accounting service port | `1813` | +| `service.ports.coa` | FreeRADIUS CoA service port | `3799` | +| `service.ports.radsec` | FreeRADIUS RadSec service port | `2083` | +| `service.ports.status` | FreeRADIUS Status service port | `18121` | +| `service.nodePorts.auth` | Specify the nodePort value for the LoadBalancer and NodePort for Authentication service types. | `""` | +| `service.nodePorts.acct` | Specify the nodePort value for the LoadBalancer and NodePort for Accounting service types. | `""` | +| `service.nodePorts.coa` | Specify the nodePort value for the LoadBalancer and NodePort for CoA service types. | `""` | +| `service.nodePorts.radsec` | Specify the nodePort value for the LoadBalancer and NodePort for RadSec service types. | `""` | +| `service.nodePorts.status` | Specify the nodePort value for the LoadBalancer and NodePort for Status service types. | `""` | +| `service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | +| `service.externalIPs` | External IP list to use with ClusterIP service type | `[]` | +| `service.loadBalancerIP` | `loadBalancerIP` if service type is `LoadBalancer` | `""` | +| `service.loadBalancerSourceRanges` | Addresses that are allowed when svc is `LoadBalancer` | `[]` | +| `service.externalTrafficPolicy` | FreeRADIUS service external traffic policy | `Cluster` | +| `service.annotations` | Additional annotations for FreeRADIUS service | `{}` | +| `service.sessionAffinity` | Session Affinity for Kubernetes service, can be `None` or `ClientIP` | `None` | +| `service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | +| `serviceAccount.create` | Specify whether a ServiceAccount should be created | `false` | +| `serviceAccount.name` | Name of the service account to use. If not set and create is true, a name is generated using the fullname template. | `""` | +| `serviceAccount.automountServiceAccountToken` | Automount service account token for the server service account | `false` | +| `serviceAccount.annotations` | Annotations for service account. Evaluated as a template. Only used if `create` is `true`. | `{}` | +| `command` | Override default container command (useful when using custom images) | `[]` | +| `extraEnvVars` | Array containing extra env vars to configure FreeRADIUS | `[]` | +| `extraEnvVarsCM` | ConfigMap containing extra env vars to configure FreeRADIUS | `""` | +| `extraEnvVarsSecret` | Secret containing extra env vars to configure FreeRADIUS | `""` | +| `rbac.create` | Specify whether RBAC resources should be created and used | `false` | +| `podSecurityContext.enabled` | Enable security context | `true` | +| `podSecurityContext.fsGroup` | Group ID for the container filesystem | `101` | +| `podSecurityContext.runAsUser` | User ID for the container | `101` | +| `containerSecurityContext.enabled` | Enabled FreeRADIUS container Security Context | `true` | +| `containerSecurityContext.runAsUser` | Set FreeRADIUS container Security Context runAsUser | `101` | +| `containerSecurityContext.runAsNonRoot` | Set FreeRADIUS container Security Context runAsNonRoot | `true` | +| `tls.enabled` | Enable TLS support for replication traffic | `false` | +| `tls.autoGenerated` | Generate automatically self-signed TLS certificates | `false` | +| `tls.autoGenerator.certmanager.enabled` | | `false` | +| `tls.certificatesSecret` | Name of the secret that contains the certificates | `"false"` | +| `tls.certFilename` | Certificate filename | `""` | +| `tls.certKeyFilename` | Certificate key filename | `""` | +| `tls.certCAFilename` | CA Certificate filename | `""` | +| `configuration` | Configuration for the FreeRADIUS server (`radiusd.conf`) | `""` | +| `configurationConfigMap` | ConfigMap with the FreeRADIUS configuration files (Note: Overrides `configuration`). The value is evaluated as a template. | `""` | +| `initdbScripts` | Specify dictionary of scripts to be run at first boot | `{}` | +| `initdbScriptsConfigMap` | ConfigMap with the initdb scripts (Note: Overrides `initdbScripts`) | `""` | +| `extraFlags` | FreeRADIUS additional command line flags | `""` | +| `replicaCount` | Desired number of cluster nodes | `3` | +| `podLabels` | Extra labels for FreeRADIUS pods | `{}` | +| `podAnnotations` | Annotations for FreeRADIUS pods | `{}` | +| `podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `nodeAffinityPreset.key` | Node label key to match. Ignored if `affinity` is set. | `""` | +| `nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set. | `[]` | +| `affinity` | Affinity for pod assignment | `{}` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `topologySpreadConstraints` | Topology Spread Constraints for pods assignment | `[]` | +| `lifecycleHooks` | for the galera container(s) to automate configuration before or after startup | `{}` | +| `containerPorts.auth` | Auth database container port | `1812` | +| `containerPorts.acct` | Acct cluster container port | `1813` | +| `containerPorts.coa` | CoA container port | `3799` | +| `containerPorts.radsec` | RadSec container port | `2083` | +| `containerPorts.status` | Status container port | `18121` | +| `persistence.enabled` | Enable persistence using PVC | `true` | +| `persistence.existingClaim` | Provide an existing `PersistentVolumeClaim` | `""` | +| `persistence.subPath` | Subdirectory of the volume to mount | `""` | +| `persistence.mountPath` | Path to mount the volume at | `/startechnica/freeradius` | +| `persistence.selector` | Selector to match an existing Persistent Volume (this value is evaluated as a template) | `{}` | +| `persistence.storageClass` | Persistent Volume Storage Class | `""` | +| `persistence.annotations` | Persistent Volume Claim annotations | `{}` | +| `persistence.labels` | Persistent Volume Claim Labels | `{}` | +| `persistence.accessModes` | Persistent Volume Access Modes | `["ReadWriteOnce"]` | +| `persistence.size` | Persistent Volume Size | `8Gi` | +| `priorityClassName` | Priority Class Name for Statefulset | `""` | +| `initContainers` | Additional init containers (this value is evaluated as a template) | `[]` | +| `sidecars` | Add additional sidecar containers (this value is evaluated as a template) | `[]` | +| `extraVolumes` | Extra volumes | `[]` | +| `extraVolumeMounts` | Mount extra volume(s) | `[]` | +| `resources.limits` | The resources limits for the container | `{}` | +| `resources.requests` | The requested resources for the container | `{}` | +| `livenessProbe.enabled` | Turn on and off liveness probe | `true` | +| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | `120` | +| `livenessProbe.periodSeconds` | How often to perform the probe | `10` | +| `livenessProbe.timeoutSeconds` | When the probe times out | `1` | +| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe | `3` | +| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe | `1` | +| `readinessProbe.enabled` | Turn on and off readiness probe | `true` | +| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | `30` | +| `readinessProbe.periodSeconds` | How often to perform the probe | `10` | +| `readinessProbe.timeoutSeconds` | When the probe times out | `1` | +| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe | `3` | +| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe | `1` | +| `startupProbe.enabled` | Turn on and off startup probe | `false` | +| `startupProbe.initialDelaySeconds` | Delay before startup probe is initiated | `120` | +| `startupProbe.periodSeconds` | How often to perform the probe | `10` | +| `startupProbe.timeoutSeconds` | When the probe times out | `1` | +| `startupProbe.failureThreshold` | Minimum consecutive failures for the probe | `48` | +| `startupProbe.successThreshold` | Minimum consecutive successes for the probe | `1` | +| `customStartupProbe` | Custom liveness probe for the Web component | `{}` | +| `customLivenessProbe` | Custom liveness probe for the Web component | `{}` | +| `customReadinessProbe` | Custom rediness probe for the Web component | `{}` | +| `podDisruptionBudget.create` | Specifies whether a Pod disruption budget should be created | `false` | +| `podDisruptionBudget.minAvailable` | Minimum number / percentage of pods that should remain scheduled | `1` | +| `podDisruptionBudget.maxUnavailable` | Maximum number / percentage of pods that may be made unavailable | `""` | +| `metrics.enabled` | Start a side-car prometheus exporter | `false` | +| `metrics.image.registry` | FreeRADIUS Prometheus exporter image registry | `""` | +| `metrics.image.repository` | FreeRADIUS Prometheus exporter image repository | `""` | +| `metrics.image.tag` | FreeRADIUS Prometheus exporter image tag (immutable tags are recommended) | `""` | +| `metrics.image.pullPolicy` | FreeRADIUS Prometheus exporter image pull policy | `IfNotPresent` | +| `metrics.image.pullSecrets` | FreeRADIUS Prometheus exporter image pull secrets | `[]` | +| `metrics.extraFlags` | FreeRADIUS Prometheus exporter additional command line flags | `[]` | +| `metrics.resources.limits` | The resources limits for the container | `{}` | +| `metrics.resources.requests` | The requested resources for the container | `{}` | +| `metrics.service.type` | Prometheus exporter service type | `ClusterIP` | +| `metrics.service.port` | Prometheus exporter service port | `9104` | +| `metrics.service.annotations` | Prometheus exporter service annotations | `{}` | +| `metrics.service.loadBalancerIP` | Load Balancer IP if the Prometheus metrics server type is `LoadBalancer` | `""` | +| `metrics.service.clusterIP` | Prometheus metrics service Cluster IP | `""` | +| `metrics.service.loadBalancerSourceRanges` | Prometheus metrics service Load Balancer sources | `[]` | +| `metrics.service.externalTrafficPolicy` | Prometheus metrics service external traffic policy | `Cluster` | +| `metrics.serviceMonitor.enabled` | if `true`, creates a Prometheus Operator ServiceMonitor (also requires `metrics.enabled` to be `true`) | `false` | +| `metrics.serviceMonitor.namespace` | Optional namespace which Prometheus is running in | `""` | +| `metrics.serviceMonitor.jobLabel` | The name of the label on the target service to use as the job name in prometheus. | `""` | +| `metrics.serviceMonitor.interval` | How frequently to scrape metrics (use by default, falling back to Prometheus' default) | `""` | +| `metrics.serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended | `""` | +| `metrics.serviceMonitor.selector` | ServiceMonitor selector labels | `{}` | +| `metrics.serviceMonitor.relabelings` | RelabelConfigs to apply to samples before scraping | `[]` | +| `metrics.serviceMonitor.metricRelabelings` | MetricRelabelConfigs to apply to samples before ingestion | `[]` | +| `metrics.serviceMonitor.honorLabels` | honorLabels chooses the metric's labels on collisions with target labels | `false` | +| `metrics.serviceMonitor.labels` | ServiceMonitor extra labels | `{}` | +| `metrics.prometheusRules.enabled` | if `true`, creates a Prometheus Operator PrometheusRule (also requires `metrics.enabled` to be `true`, and makes little sense without ServiceMonitor) | `false` | +| `metrics.prometheusRules.additionalLabels` | Additional labels to add to the PrometheusRule so it is picked up by the operator | `{}` | +| `metrics.prometheusRules.rules` | PrometheusRule rules to configure | `{}` | + + +### Custom FreeRADIUS enabled mods parameters + +| Name | Description | Value | +| ------------------------------------------ | --------------------------------------------------- | ----------------- | +| `modsEnabled.sql.enabled` | Enable FreeRADIUS SQL module | `false` | +| `modsEnabled.sql.dialect` | The driver module used to execute the queries. | `mysql` | +| `modsEnabled.sql.table.acct1` | Tables containing 'accounting' items | `radacct` | +| `modsEnabled.sql.table.acct2` | Tables containing 'accounting' items | `radacct` | +| `modsEnabled.sql.table.authcheck` | Tables containing 'check' items | `radcheck` | +| `modsEnabled.sql.table.authreply` | Tables containing 'reply' items | `radreply` | +| `modsEnabled.sql.table.client` | Table to keep radius client info | `nas` | +| `modsEnabled.sql.table.groupcheck` | Tables containing 'check' items | `radgroupcheck` | +| `modsEnabled.sql.table.groupreply` | Tables containing 'reply' items | `radgroupreply` | +| `modsEnabled.sql.table.postauth` | Allow for storing data after authentication | `radpostauth` | +| `modsEnabled.sql.table.usergroup` | Table to keep group info | `radusergroup` | +| `modsEnabled.sql.tls.enabled` | Enable FreeRADIUS SQL TLS module | `false` | +| `modsEnabled.sql.tls.autoGenerated` | | `false` | +| `modsEnabled.sql.tls.certificatesSecret` | | `""` | +| `modsEnabled.sql.tls.certFilename` | | `""` | +| `modsEnabled.sql.tls.certKeyFilename` | | `""` | +| `modsEnabled.sql.tls.certCAFilename` | | `""` | +| `modsEnabled.sql.tls.existingTlsSecret` | | `""` | +| `modsEnabled.sql.tls.privateKeyPassword` | | `""` | + + +### Custom FreeRADIUS enabled sites parameters + +| Name | Description | Value | +| ------------------------------------------ | ------------------------------------------------------------------------------- | ----------------- | +| `sitesEnabled.coa.enabled` | Enable FreeRADIUS coa service | `false` | +| `sitesEnabled.status.enabled` | Enable FreeRADIUS status service | `true` | +| `sitesEnabled.tls.enabled` | Enable FreeRADIUS radsec service | `false` | +| `sitesEnabled.tls.cipher` | | `false` | +| `sitesEnabled.tls.privateKeyPassword` | | `false` | + + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +helm install my-release \ + --set imagePullPolicy=Always \ + startechnica/freeradius +``` + +The above command sets the `imagePullPolicy` to `Always`. + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```console +helm install my-release startechnica/freeradius -f values.yaml +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + +## Configuration and installation details + +### Adding extra environment variables + +In case you want to add extra environment variables (useful for advanced operations like custom init scripts), you can use the `extraEnvVars` property. + +```yaml +extraEnvVars: + - name: LOG_LEVEL + value: error +``` + +Alternatively, you can use a ConfigMap or a Secret with the environment variables. To do so, use the `extraEnvVarsCM` or the `extraEnvVarsSecret` values. + +### Setting Pod's affinity + +This chart allows you to set your custom affinity using the `affinity` parameter. Find more information about Pod's affinity in the [kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). + +### Deploying extra resources + +There are cases where you may want to deploy extra objects, such a ConfigMap containing your app's configuration or some extra deployment with a micro service used by your app. For covering this case, the chart allows adding the full specification of other objects using the `extraDeploy` parameter. + +## Troubleshooting + +Find more information about how to deal with common errors related to Startechnica's Helm charts in [this troubleshooting guide](https://startechnica.github.io/doc/troubleshoot-helm-chart-issues). + +## Upgrading + +## License + +Copyright © 2023 Startechnica + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/archive/coa-master b/archive/coa-master new file mode 100644 index 0000000..039e3d8 --- /dev/null +++ b/archive/coa-master @@ -0,0 +1,55 @@ +# -*- text -*- +###################################################################### +# +# Sample virtual server for receiving a CoA or Disconnect-Request packet. +# +server coa { + namespace = $ENV{FREERADIUS_SITES_NAMESPACE} + + # Listen on the CoA port. + # + # This uses the normal set of clients, with the same secret as for + # authentication and accounting. + # + listen { + type = CoA-Request + type = Disconnect-Request + + transport = udp + + udp { + ipaddr = $ENV{FREERADIUS_SITES_COA_LISTEN} + port = $ENV{FREERADIUS_SITES_COA_PORT} + } + } + + # Receive a CoA request + recv CoA-Request { + ok + } + + # Send a CoA ACK + send CoA-ACK { + ok + } + + # Send a CoA NAK + send CoA-NAK { + ok + } + + # Receive a Disconnect request + recv Disconnect-Request { + ok + } + + # Send a Disconnect ACK + send Disconnect-ACK { + ok + } + + # Send a Disconnect NAK + send Disconnect-NAK { + ok + } +} \ No newline at end of file diff --git a/archive/tls-master b/archive/tls-master new file mode 100644 index 0000000..5271f55 --- /dev/null +++ b/archive/tls-master @@ -0,0 +1,247 @@ +###################################################################### +# +# RADIUS over TLS +# +###################################################################### + +server radsec { + listen { + transport = tls + + type = Access-Request + type = Accounting-Request + + tls { + + ipaddr = $ENV{FREERADIUS_SITES_TLS_LISTEN} + port = $ENV{FREERADIUS_SITES_TLS_PORT} + + # Connection limiting for sockets with "proto = tcp". + # + limit { + # Limit the number of simultaneous TCP connections to the socket + # + # The default is 16. + # Setting this to 0 means "no limit" + max_connections = 16 + + # The per-socket "max_requests" option does not exist. + + # The lifetime, in seconds, of a TCP connection. After this lifetime, the connection will be closed. + # + # Setting this to 0 means "forever". + lifetime = 0 + + # The idle timeout, in seconds, of a TCP connection. + # If no packets have been received over the connection for this time, the connection will be closed. + # Setting this to 0 means "no timeout". + # + # We STRONGLY RECOMMEND that you set an idle timeout. + idle_timeout = 30 + } + + private_key_password = $ENV{FREERADIUS_SITES_TLS_PRIVKEY_PASSWORD} + private_key_file = $ENV{FREERADIUS_SITES_TLS_PRIVKEY_FILE} + + # If Private key & Certificate are located in the same file, then private_key_file & + # certificate_file must contain the same file name. + # + # If ca_file (below) is not used, then the certificate_file below MUST include not only the server certificate, but ALSO all + # of the CA certificates used to sign the server certificate. + certificate_file = $ENV{FREERADIUS_SITES_TLS_CERTIFICATE_FILE} + + # Trusted Root CA list + # + # ALL of the CA's in this list will be trusted to issue client certificates for authentication. + # + # In general, you should use self-signed certificates for 802.1x (EAP) authentication. + # In that case, this CA file should contain *one* CA certificate. + # + # This parameter is used only for EAP-TLS, when you issue client certificates. If you do not use client certificates, and you do not want + # to permit EAP-TLS authentication, then delete this configuration item. + ca_file = $ENV{FREERADIUS_SITES_TLS_CA_FILE} + + # + # For DH cipher suites to work, you have to run OpenSSL to create the DH file first: + # + # openssl dhparam -out certs/dh 1024 + dh_file = ${certdir}/dh + + # + # If your system doesn't have /dev/urandom, you will need to create this file, and periodically change its contents. + # For security reasons, FreeRADIUS doesn't write to files in its configuration directory. + # random_file = /dev/urandom + + # + # The default fragment size is 1K. However, it's possible to send much more data than that over a TCP connection. The upper limit is 64K. + # Setting the fragment size to more than 1K means that there are fewer round trips when setting up a TLS connection. But only if the certificates are large. + fragment_size = 8192 + + # include_length is a flag which is by default set to yes If set to yes, Total Length of the message is + # included in EVERY packet we send. + # If set to no, Total Length of the message is included ONLY in the First packet of a fragment series. + # include_length = yes + + # Check the Certificate Revocation List + # + # 1) Copy CA certificates and CRLs to same directory. + # 2) Execute 'c_rehash '. + # 'c_rehash' is OpenSSL's command. + # 3) uncomment the line below. + # 5) Restart radiusd + # check_crl = yes + ca_path = ${cadir} + + # Accept an expired Certificate Revocation List + # + # allow_expired_crl = no + + # Accept a not-yet-valid Certificate Revocation List + # + # allow_not_yet_valid_crl = no + + # + # If check_cert_issuer is set, the value will + # be checked against the DN of the issuer in + # the client certificate. If the values do not + # match, the certificate verification will fail, + # rejecting the user. + # + # This check can be done more generally by checking + # the value of the TLS-Client-Cert-Issuer attribute. + # This check can be done via any mechanism you choose. + # + # check_cert_issuer = "/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd" + + # + # If check_cert_cn is set, the value will + # be xlat'ed and checked against the CN + # in the client certificate. If the values + # do not match, the certificate verification + # will fail rejecting the user. + # + # This check is done only if the previous + # "check_cert_issuer" is not set, or if + # the check succeeds. + # + # This check can be done more generally by checking + # the value of the TLS-Client-Cert-Common-Name attribute. + # This check can be done via any mechanism you choose. + # + # check_cert_cn = %{User-Name} + # + # Set this option to specify the allowed + # TLS cipher suites. The format is listed + # in "man 1 ciphers". + cipher_list = "DEFAULT" + + # If enabled, OpenSSL will use server cipher list + # (possibly defined by cipher_list option above) + # for choosing right cipher suite rather than + # using client-specified list which is OpenSSl default + # behavior. Having it set to 'yes' is best practice + # for TLS. + cipher_server_preference = yes + + # + # Session resumption / fast reauthentication + # cache. + # + # The cache contains the following information: + # + # session Id - unique identifier, managed by SSL + # User-Name - from the Access-Accept + # Stripped-User-Name - from the Access-Request + # Cached-Session-Policy - from the Access-Accept + # + # The "Cached-Session-Policy" is the name of a + # policy which should be applied to the cached + # session. This policy can be used to assign + # VLANs, IP addresses, etc. It serves as a useful + # way to re-apply the policy from the original + # Access-Accept to the subsequent Access-Accept + # for the cached session. + # + # On session resumption, these attributes are + # copied from the cache, and placed into the + # reply list. + # + # You probably also want "use_tunneled_reply = yes" + # when using fast session resumption. + # + cache { + # + # Lifetime of the cached entries, in hours. + # The sessions will be deleted after this + # time. + # + lifetime = 24 # hours + + # + # Internal "name" of the session cache. + # Used to distinguish which TLS context + # sessions belong to. + # + # The server will generate a random value + # if unset. This will change across server + # restart so you MUST set the "name" if you + # want to persist sessions (see below). + # + # If you use IPv6, change the "ipaddr" below + # to "ipv6addr" + # + #name = "TLS ${..ipaddr} ${..port} ${..proto}" + + # + # Simple directory-based storage of sessions. + # Two files per session will be written, the SSL + # state and the cached VPs. This will persist session + # across server restarts. + # + # The server will need write perms, and the directory + # should be secured from anyone else. You might want + # a script to remove old files from here periodically: + # + # find ${logdir}/tlscache -mtime +2 -exec rm -f {} \; + # + # This feature REQUIRES "name" option be set above. + # + #persist_dir = "${logdir}/tlscache" + } + + # Require a client certificate. + # + require_client_cert = yes + + # + # As of version 2.1.10, client certificates can be validated via an external command. This allows dynamic CRLs or OCSP to be used. + # + # This configuration is commented out in the default configuration. Uncomment it, and configure the correct paths below to enable it. + # + verify { + # A temporary directory where the client certificates are stored. This directory MUST be owned by the UID of the server, + # and MUST not be accessible by any other users. When the server starts, it will do "chmod go-rwx" on the directory, for + # security reasons. The directory MUST exist when the server starts. + # + # You should also delete all of the files in the directory when the server starts. + tmpdir = /startechnica/freeradius/tmp + + # The command used to verify the client cert. We recommend using the OpenSSL command-line tool. + # + # The ${..ca_path} text is a reference to the ca_path variable defined above. + # + # The %{TLS-Client-Cert-Filename} is the name of the temporary file containing the cert in PEM format. This file is automatically + # deleted by the server when the command returns. + # client = "/path/to/openssl verify -CApath ${..ca_path} %{TLS-Client-Cert-Filename}" + } + } + } + + recv Access-Request { + ok + } + + recv Accounting-Request { + ok + } +} \ No newline at end of file diff --git a/charts/mariadb-20.5.9.tgz b/charts/mariadb-20.5.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..017dc9cf2be0360d1bd5014f155196e312e47a1b GIT binary patch literal 77309 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 ICICJO04yoU*#H0l literal 0 HcmV?d00001 diff --git a/charts/st-common-0.1.12.tgz b/charts/st-common-0.1.12.tgz new file mode 100644 index 0000000000000000000000000000000000000000..f32e3fe2b4428d1afb40e705660933451643c1c7 GIT binary patch literal 23576 zcmV)%K#jj2iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0POwwcH21iAddInJ}2*hVNz38wM8vU-EO!0?C41S+wFGC|Mm{MhkxiDJ%9e}`O&kZe*X{M-eIr*^berB zX+-LtlncoI&|SN&a_1h%0|}u53QP$<-U9$Kfrl^<<8FEDc1;&>l?iuZVF4YSQ0>Ns|5S`aQqb-z&BT-rxa)YzlrtQ4Ev-gCS*L#Aupe zG6Gt(K}1J500Sg$5F+4GKqgQyCOCi~kd?T<2f)=BbNv%w4hR(>L`g)aa1bFdm;x*~ ziiZB)n8xTBjD<+}ai=rFidF%QJKTZWfl0zUf+5t2AtoK&Oh@ChhXaYe1>x574LnRW z1RTQ=;;M+BkkQ^Xn%+>D*r161EKlijxQmwATj1lmwDWd)MgzWmNq3KVJ0w ze%J4|yWj3f#010yF$E6A5J$&gh*=B?pThBfClHg-h(?h3Sh8EP(Jess07zMs_ay)1 z7whVpnXcL6G-Ux&%{HLIo|q=+7(|-cdy|q(-1QK8&`+-aCooD8zYPPhK>v4p&!3j{ z|KaoAPXBM?dHfg@^j1DbA3p|XN)zuvWk zuWW|^T&Vh z=;>kE|9jT&b$8=`8_(~*cfNbHcS@5f!=teP`#}rzyZxu&hs>6PceyPGCs710WJwM# z5Jzl+LjTd;<@u}s)qaBmL^x`ng@_0|#E2b(lk=0)pI*27e)rMdcbzX^9_>BalTCsN zj*kIH0t|74q3^9B@7J_V<>!;GE7F7!5D>Ugvsb^L}>Q<^(Pdh%B_90Cmn5F3y}b+7xIar z2*$5JB@A({{B`?5Ip%1341WI|_}6F(WV0Z9Xo46Nlu38neXo0b?7jj(_K!)YANcxv z37Bk4HUmC`-%=`2<+B8UNSM99K~h?dK~K|8erngUcMMs$HhU$IEwEQNqv~1fxCD14 zj7t=uKu~stSZsOFet;~V&(k&8nQ>Ao2oHFARNWq54NG+o@erWjfG?Z2En7mU&yAIh z??OcpM@7(DmX-yrYZXCTHq7UVpb3rWX!XoH6b@Mg8T-UZ`)72ku+&SptA* zB*$|)K#U-PxQq;Y?^)vLpeG6G{*fnP3Jf7c_nY z2Ponm@PF0ORYF7k3V7&~VDPOR@a00~FLh)#_0RJzDNRxWQvPgey@N602@ITpL+q=b z=ltkV~ zfsy%wgcq5W3yp970<9MK3l$j|B*nw3r5U@@N8i0Vd-7>Fb?=^=(lh*+lg)LUtX3R)uP^Y;}L zs{Jm$aa7&$3~ZLMNp6W&ol{!idHsmiweIZ*d-Ammv8qzuN;}788OLRXShzhyd)}#cQngym^yUV%W}VJl)hTJNFLw^fEQe$Z zR->{1ai=3?hL`bRhRS^BV)dc2B>`#ZE^O3O*kbxkH@B(mo0ECiaPrM@4Ho9!?s{sc z(NjDB7r+D#aI~oz!1?ok{oY~sS$Y2NY42z^|F@0j!OZ`OF#-az5fb3%%vb=k7HGbn zDTuSP9?Eg=b1&Qc;h(yde$FfT=HDz{aR9c!{=R)Zis%4Ft>Wi}8eFhcX(-v-d^H@v z9Pl(rC=)1rwD${#BXm4Vi5GgC!;oq#*XR>V0dF8JVrL?wC)ZUfz#{UU&;7sU7Rg&-boo`@xSpXqGFo7tqj-YYDUB1z5b*w6&+qrzU9VU!hp4>t8AMu;Wzg6Fj2%qcvjS@Rxlq^YbTV+S|Rf!%#6jQ>NQ}ubJ`$zcR(QW7& zwTgc8#8*25VnmjseqL)w{&mRD1r%tQMoUV+TkT;oz>xC}Nsq~hAZur0hX18@;VsFRc>p#%@=q^bEyb3Ah4+yw4Mqt}a6U$tWXO!V8|KBy`Pn666C9vr zI06%FYu!V}bQ>{-p%LbStuj_-*4{94ev)I65& zHDjd1IlRI{;7fk=s|+xdz+}{!^i`RKJgZch&8@}tH_Yf?5feCAi_Me!%;sK$P`E(g z4SF;Er>nHRoIEW%@OhS=Kd0d(3Q~r}RHyDr8T#hASDyG;z1va6l+{vwDWb2Mxy~te z62@5VX*s22h)1c`!K;!D)QLVZfhB%jhg^bh~&KiWG1H*g9B1;H2v*E5RWKz$|)CW6s04NwSDB5;%yIP?$w zu3k@AoZFRP3>^=^%@_w`Al)N~2?vk>7=~(16pVoP`dNvLXj%N>lp!jN260xP~u*Ixj(;QW`P!{@#7`mg7Q&v)y;w(;Ee^=3Iqy)l-MChI2$p(2csb3MWMOsaPj)z%GIi>m56%dn zVvJZ;k%I_dqnz^K#@d|>T*?var~}!|X#_xwp#ULOw(EwnYd}*W?WV+NKtE|4E`Kn@ z1;dih?MV+@o}MnrSiLpivPgw&2^>d3_R3BQ8ONYfY014rjnK$lU>L$gpwPB;`~vtn zaygszB-iX!afMb}xm*=uP8-JlR#|$d!IW^%g;OC}AT5))@^G!RQn9KkNhsOG+1(pTo-3qWHmDzCjE|53K+0gt8Rg#W@3 zvwxcpZ5OQBN#O{C&(Rx9(ogTzQa@hm=h@HLL=ic&I~bUXarek0|b^5A|*iu z3RVlsA&@XU!4Vpv5X3Yr(Wiu!?-X94OKxo8HS1w}1}H?}AVQ(1LW;k@INF5_^-rz; zuR_Vqoc;EP#pl2EpLhEu|NrUX^PT^{mFNEY{~EKaF{3v+x1kkPnv57!PHf8Mf3+z{ zAm{2}+=4ZiAe9Ln7?a`4_FW(HNp9a>%Qm{*8A-^z95<(C`Lg*4`3i7x|Eb>Xo2G1cwMA$+La_)<0>)PK+e~({) ze^N};`2|&C6ru&`0#yN2ws@cMUo<8~&+dsr(-8Og1@JzS^OMWV5AQEtU4qva7w<2Q z!Cz>qN2=L61Ew@(AV`^_Mn1Aj!(V%_x^-_(t1nERyYSNcNI>~{M+MS)15FSCa3~N1 z3}M0rj3U+h13;q?1Pmz^2O}9LPo*djghCxEi!qwox7R2U%7>DXKNqq)6B?y40zm|E z%r}Gg4=GbYIVLhB*Mb^AA`zei8^eq2pzV+b+#g^;V2std$7^>+Wqf5&U@e1GT6Qu;|R4g&Y1FsH)UVHQ6Il4*D`y>3+1X(`56o$ zjuwX!GmQ&nc!UXzTo+iKz^|*H&T<;Hs@`+ug!2UOVXy&#uj!) z+7A`<-P*%6(g?}w@8}g&TGpPd@D1;%^Aief_zWeKV?pPEDndC{P-@!p1ss*^g_`Qj zCfMpKl_=S&O?o&W3fRxCoYAu=PcHyW5;^iKUrIeLr6kPsZ4nojb`3Bo$gPV=;lq49 zW~4@D5Np50G#6pXtkweRm&cNebm7Acr0470Jf}h#*dGb7A0bjoeE?(sUL!^AVFq=xyhyEj`JPi_{12ACp8WGdUA%Y@hi0h82l>{7=ySEUa9?C z+OlVN#i-c|LP?toNJ7ZMJ0z($v;VUkt&ijvx1U<5j|*_L>5?iYfTBi=mf5h1N81Lo z&QmGOT4ZX@3u$nTn2%}4c(NU@s@dk1PZ)~p>MX`SQy3qF6xL(2QR->X~q6aY!u}V?ZV$xs;JX48<8d}ozrG9 z-cF?&#Ivtetmh;10ZtQ&iD<^J8(UftC?~sClJiS{mOcszz_Ua3Cyp=E;ShfUUfY|+ z%{+W=TUcIG);4Ocp0Q2HRl~zY^wRuUifFpZ3Y2RkM)T-!*P8I(^QpD}+WXno{C~Iq ztUCYS-`W4IJmvZSmyE(Npz#4XBf<8k`<-n{38P6C!YU`=(calG_y1J{65 zHSPgDUjP1%8D!|?vj_Y8i>Eg7B(a59fK;3=P&GJ8pt^BP1)Ik%axUqM zkR;QbEgr?Ruv#KlEL+I`_?mNtXv=Ntg(=~mWW233Hh+1cZYD>;$X21nyx%W?_utFe zj}kr=P-T4T5GXRYW)4)(>d60cri?z#6%|4Zj1SJkoz|C%}di~ zD?qAFe$|ZIVqZ&>s)bK3>=HI}JHBey>pQm#J1j z=`%+4P?BcK0zEQHHpA&CmqP_nm|xvldTHxq<&WKO$P>HDyP~FBcQ782e1BCq}3* zW~I}D=t9MwY7=^*w>{NND!zqWJF+3~=))K~gNP0~{lnqYUWg9Ahu!a=JqwUU|GliP z{}%pJh5^}6Ox&O6s>h3Bjhd)!K`3$88I!N;sn7qJvr)G*|Myh>U7r8zKilR1w(;DX z{GYXQKdRN}0s(2DKADoG7`M6+^@JKD)5EO)XI7Di<#T3Sob520Evjv*1FMu+M zCnf@oP<2UWGUI*U5nH(toY znO*X319c}ix2mOPAF^y(aKu1+gsxmT1teDs1r(dB2Gx93LPll+1t5{|3Q?XMi88X# z%=M}b0Z;?7@YP+aBxz_M&29^9)oBS;0uGV{AoOnFfi?sxk zA%r<}lt_5_K_AugWOXqjp*WPTeD^>41Zg9?1r6JdhsC`a$@Rk~H6~34z z-5Gg1qksIuYP-rM$=YzuU%ux$x84{2BV!$fn8zfwiRc(HwFtz?L+6u5 zh5NEC4y~Fy=36zcdp%ocT_jy#tb$hH>HKPztDwGJ%TVoh7kF7;A!lc?isfXHkrf8k z12udyiE{V;?fEM=DxQ(yhdM}>5`g146>tz`Cn51P7z4E>FNx^X=LrgYZmw2$uSu7N zo=<{efdz`Ec+2`c-ILI8rs8?D_W^-W9VB7*0!5T2fKCtt8l2ICW@^Q3>50|m92NIl zY&j+Y0$6;jF3g=~d(u=+#U=$9g4fQ)X8gb=4)_5;BJdyW{X}oj1hE4R3CGf}Gnh%F zZWva3Mo?K#JBI+XM|--c-d=)YwQ~ds7(xLJ{S1p1^&>% z|K78wJN>_n=l<^heElhrKD^ZX#LSSY!)a9@Id9XW>r$3?JDNCDAB1F-tStF{f*8YL z!<}!19hs*LL1FOHn5wPuCd`E<1|3Xu>~&bwpbsWwx9yhnd!aA-?|kEfIm!TdfAoO& z_l3HBcE4aoJ83nh;I|Y;lD(mfI?d+X4@g5-<%MiRV$QSUq&ba|J4>HW1?fqL2*=n= zMXMtR_6@aOy}OiU)r5G0f|kE`HneB{X&~7N9}f9(KFzI2udZs5$S>YXTsDt28!hd} zOk!-AnFW^GOsP^@q`a?Zk<>bP=I3T9D8+Co!?o~sX#~rHSb+AV`QF=_&9E!Tp=WJ_jgN?y*K!Dtc*>c_7pZD|FlT)4b?W$`$vMavyB zPP=o)&D>HO7(5w;icK{gK(!f=9QnGhYY(VesGA;GCs9Oi++$SpLj}wMw^WlSMEZ6( zb;3(KFXSW(0VW`z@jxBkqmSolXrpHwOHk;#ZqC(w>dpE_8_qOp>RvE&Mv{91?6HYfMulYfZOOqXu$pkW9OLy~aRl+x{z8>W>{BN1`cb!dn zcu#Hqj}2h3x%A({`JevLQ7Qj-^!#~mm;c+wbAR)H*?Qu9zoXq10fT_1#KhNy-3n?C zMH1lvi~7>~wy!<2#MNvjmx%b_Y?vn-vA%6st%f!6yY*}Z1qiDHOlPSuy@*&fexlp< z17!{Nuvs2WSq4rW!+eAJd~a5b$Rf;aHp@99#pv|f#!XRKc-2GeN^psuf!`}`0xq}V znLoUSV0I^iZS$$u|A^C+1)G`!TA=@*_xhFlf4k3*cKUxC&wbbb>XvmajcP{&;-aJS zv-Y~j0W?eeAQ<5ZA|PRiBjN8|jS)xYm(J@BDU-!G>F$b!;|Ct1dpI zVHyZb$&B1=K1y^WSxQ!@jXWNKgz8mgb2WPfiq?Le@6_fw)mM$a&eSOqaET8?(9A47 z?S2FH(Wd|<0-$7!V#Hw7=7KUf($i6&BFILl)7Sq3j{k*tE5quErIKB4ya#|c;_bsv zJcdzZJ7$ho@GKH}4mwFa;63fe9`IrmQ#SR0*Xw`(7JI;}Af$@E#a_$8(|xQ!D}noQ z7O?)023AX}R0c$GP{ZcFar_a_w`tbSF0=UEPkDAN%QqdF=s$I%-UW~V7K1k}O<)x^HO z8}`5h``2j7GYncS=MtS+IrzH{Xm`(2Pi_83FPGoa`A_{`zh7DZ`}A;^|JllO|M!1n z2SRD7v`4`&IzqzAaAC1raX&@f(>WB%9&hbTUij+BCY|~+>lF1qOKG?Y87*}twp~V@O+OH1tbslp z1lu$i)u#j5i_!Q0nQ~#am1b;cnUq>^eFIsTAI^m%tnS*EDEtwVAw6zzo10(=bz+D~ z{y}l_vF*QZSd+EF6!!}EoRnwk@G7$jIGRe6dxP|~XBTot7? z-`s8&Gd7y2DV}4MZ*r<3R<+W&L>0`Cxa$AJl4dCU0;OxRu$F5e6qH2}T0w9I$ zPZsm~4gKZAbrzN`qMVb%(qi^b^Rj-rM$;wK(>0o|rJYoL`Cm01xKlyfQ$fRXs3h083> zF|rb&7bZ}dQ|(EP`JD5Zn+(PbPNT7yK+bO{3jt+-A;B=3ASrKZsX)XK45vWPjyJhO z-!jKS<-R@x!#Orm4_xzyU4CC2qrgiTo!}6KzZMP>@$4|S;Co*6UEgZ~FG6G_#vbT( z6;r8XsybV&xEsLzdrS#s=cRUSokfRM8nsaob2y1AzR|vGn%%Z&Ahq&j%lH z6ajTS#1JzsoZEBtnWXj}A`Q&os<{T*>JYL<9NJ1KCv@>ut$3Yvs zq%=a16k&ZBBega~PyoXa@M%1t5x1RQ1Uugh2wE|6mfqJmdHL)Jk)T1#swKB+iOK;W)U{h`IgwP&1Ei*}pB({2 z0ya%VHY{YL|5KfPvre1p^c8Nz64_Ei?fQjLmOy>Vx8m7Yp>p(_7-j7L&V z6Nag}1zn6GDII~UZLJ)*l!fZTXmB&e!C3Fg8m2_e&P&Cv7K*{L)>jIw=Yw;rd@LSd zf?>sf!NXb-yih$dMsNRYsLV&MmbhxoZWcq}+hSk8b##N>PL?6A&ec_VDAP>PRdp_Q zkc40iO@#u5Eizga$?8T4>93agno1~a$*%OJ!==q%M(>LHcKQr!l)LPSlBASK=44Cf zG9p`wa8q**CG>9yLYb6k>R6c)L2aK;l-@Nas7iFhVPi1O<>7i!jv|Qu@NL2DYLxPpW$zpW zn|a+;$Ifv>pJW&wzW|<>d8<#XaVx*ijj6L6(evC5iCI|-+qeQwgPvrTdtY$E_IKa^0N%!J!mA+WL&H_mqz;^6%fBp6Mk{-yUIy51A=q4 z%S;4h-*Qj|hRuLFi(k!Dp-UHUAp!>x3PCA+&Q!+>S6$SG$p!F>g~K#p4}m^+ zbeD5h-Osbfpp9j%M0je0yr(6@vxs|6A8LkeC0|g+=e6|4XQ&Swp;5wpW4JgbqX_xx ziYBk7ca=NAa_$*WueJMc?^K(CQ27q7DsnoE@Y7_(V2B*cVQ|Y&1S~Y{&B3Ww?bY6g zSQIrA5LQL&Qn0L}`w_iC4D3szdlDsM2zsrS{`oGA5yJuKwZMLwB-K)%fu0clyH{?+ z88NB~4=}D6vpIFp2z|QHCzYH;(HksOO5XeU@qd3|AfGHc^=>Qj!m<6)}HxT?|KLB1UZs5K8*a8pCMveqfGd6lLaJMAPa zo2N6a{c2A2w5PsJwJmtac{8_XGr-(=zHHefQ8O3cNLLA6K`L#g_VjOdU^zr63D=eG>z|$9I zH@eun)Sjbb^#_Hl(zMw%+=VZn^Rts26lRslftWX!_2s+j#D;{~=L2sO8R zfa3KYHAbV75&+f*zQray)i)13fl1QfX1i*uH9>G?vDn1Mf`}2wruM~t{(>{m-jV)ibg^t5!er)koC>#&nNx`ilD#~bg3$|zkJC8OD|8c zc`dMSu5ZxyOf&NM5)IQtme8KDVy#@&R4dO^)CRn76~0jCY3b0eo0uW# za46K}j*^4+#vk7TNf-)Hs9YCyS2EFVgwQk`3y~amI&psCy>He+V%p&e!=sKQ8u!N{ zjvgyAw&kc)e>ERA_O>igdtKHn$?nbm)Nj>{tY(sKaB(hHfyXm-9dU{_gz0tvvVf{3nHzzOWq= zE|@-rNv+WxA(5~1)U!qN575`5Y$m@(NElr?Kk;vtI@q_WPTRh0eoFp~wzHG!Cy?3w zT{AIPtzOaBWb!Ly_M~6*DWOaNsg^B_FJE3f*}qN)C=ijNlAWD!&TC(E179hf?_9rW zuHrX&e9)%gpPUkDJzsdgtNAQnme9Amf03^FXS=ew9kyyt$97e&PPIlYhvRbE=0+2J8v{cVjPwN!Ql&C8A5Vw+EC)TA2QUHF?R`>OwO8VI zX|i|UP8{dR6y?PE@WPqHtsMN2P4!MB3-i456BF;ZzkC5T5@hFj^^yQfLua*dVNn2} z%#<{fs%jvqZCnu`l(bFhhJrVHIc#Y&)-{^;iqfdIV67mJg(fqJGCTVW5!CYU>>EQ9 z#5np{zC3;b%uiFQC~I!fGOJf!oLe7Iw16wlj$D*B1^RQ(be*}guTE4>$0)ewX$+tf zxf&*UHmX(UIfC!>62b5Cx%U0+AoBye;c-YANV!_VlF$%9La5LS4G#eNBuQnj{;*dQ zgME$=c-;H`@cFY=BbOsEIA0lrGtz3Ly-uLeieaMG&a9y0sx4%aL$!vo$nBdW->tr~ zHT;*5qjRZLR3zMTO@9_7YM_9|SZKf=Oz^MvK6URJ6J>7=p}agu{0#UQ_MbkJjH|UF zFU@^SbO?SzQ49v@2<+GF(jBA7{0DQMBHlUdc6+S@T`8bsf|yc-B3~*tj3^Y(jsT96 z2nQmX9;i#NLI3&D_lJkizyJj_MjZ5g{Q~{5`^?|F8e^_6!q#imXeyFa03;m~wZ|=$ z(q+6NK~3Jo-`o3zqtZ?cReVa*?Cx&qlj*y$S-ysfl4z<kb@f(MZR8=f&^mxI4{*9X*@uzfpe;gzi01M`NI7IlCgzMFeu+3P&|Uj zQ42(p-gg%e?G6mOr%!GCe*>9Rr<+Ov%#Z(jy`z3*{m1j}^IiPEjpx44|9#M+2;hLG z!suT{qevNOI9fQHmx;2ebOlHC(`z_}BXmKjSeWvy1=+6bgxSw$!R%=g9`G4TD93`b zX$$PDZ5+OUqvBdiwJiPzOhVwb*~gFJAD?{Imh{+b>5TM;lZ$s}?|wW67da_Fhy)4* z3cC*iAowuak=Gu zCISwJN}%)?H+zw72E;_XMO=1KMKQ2==#C{r4j^+u^^K+{x##U08kXlr+}AcClSUe( z-CSwni2XdC=zPPE)q#c#jW8E%S{M*=D75O1O3CkjEVfbVNpTNenNE3Lru1Po{Oq<9 zm)0+wHM9-(loTs#dH#R@=l_Ds*QdW+oL&6|WcuX2=_kksh~BP0K#1rqI9Q}YAAE(m zalzI0uN%lgh&Ub*6dtG(_T|6oE@ZuRKp)euE|E+k1f;Vuq%7t}wLrVmH&Awg4#7*U zHWiF3sRF=Bt^&ZRRsjyCKDe|9N`PuBiQ5s(RS*zOrB>6SM~Kw^Ew!LLRp$`M#uCIN zW{?Ev01OztM#OY-h@eOr;<{ro<_dL3@#U9%sVxbYImN7!uxk3)74x#FXvVfx-gW*e zf(B~J++-tcP@9Fu<_ZO=$JGTl*>#>vm{ogyftyoT1G+_dfc+Aq;}D7zz6xVQTe{}9XK^1aCYm3K^_<=>YxM70480weM%6BAtsIxTh^(8 z+cHjNc@M2gff_=1IhD%lx6;q5md`$UWnwo`;`OIu6;{yJkp?o9tJDgeIM|P=DhUZ# zmPSvmP2y1{vUQ5Qgv4>2f5IeF|%TD{37FBfs96}+H`7hW2~v`Zk$pt{F$t%l^I*DUT6$~%$;Jk z>=<%jwt~OV14$iBri|JtO^JBXJpdt9?O08Sh12^C6BS`N+r%^~26hpVtWFtmTe?`- zU~bV=GU_6*(vWamA6FImt!mqghDj}dif1R(6UU{q*8*jTTAT?&A%Gx&dRwZXDz9j7 zj@M~5(6#r&34L~)I^>GzlGAMIeUWH(k^QJvf*j1iX9=hUx;3=vd{>Yb@E@T2pm0Oml5kCFyPSv`If}HAKyshD-V6nHzqk^t;sUt}V&P;A(B_ z-TB}b<%{MO&dq&NMpoUZen^=UxclIT!tcU`=RC_7a5Tf^fk8l7Xoky_rVQLrb{$a| zs^P@zJ>85ebA8=n7U4P_AV!ct+{d&N(tvjYN&=J!Zst=`rm*hl1AN*UF`S6MGtYy* z>wMg{pSt{S028PVP{oLM{tnrQCXD`b^obBnhJl!)gLJn}t;B?1YVIAwMuLEOI5>w*u}|_T4GY!f_g>Zq1YPGgFHDKS2(> zY^-3~ne7mGXBfuQo6CUy)juNUTM$OCDOo62 z-lS}F%D`6@meqOJ2!(sW%!T85hO_mx4C%Su+l}fa;=A3zzFmIawF|R*)_5BD|A+~l zO=T+v0So;9=TH0P{9muz+nxWlmFNDh|6IyQNFi-oDQ)WTAtv6MDyte(w^@~Isa3nP zN^Qr0y3K=A#3XM5D9|!=GS%JM8zWiAf%<^RccCwtUXO|v$gL350KfM%jZ!WUJL5cE zZtz-i7V2-1k}ll)PQ;a|w{fyP40@fMzJ0xdp*RWRl{Fufb(>j?`9-%+t~yH1inbhg zac5PVl4@sI8yVK62)VPZ4Qy)zitfzoJoCDkfIADjB*7lGk-h7Pez~VX{)Z%^^)>=8 z%K!BHPs{VaM@PH;zgu~}lKjtUMAML{lU~93k4^o0l8nwN7bAxFZ_&yV0yzXVRA%a% zc?GvLm9mIRvvl*nIiX&{;5to~FlKoVPDwH{)i+7Dj)wUlsAnC$7>tJn^ zt~CujBqFa%*jpjygCO85DBu9{W#acD1v3B}C834-AZWOeA%1&f`@s$Bb4sH%#EZ!S8kRB(&FvZTUCFKQ55@v(&!os1666me#Ze`r$T2|+^Sh>M!^}@=&L2-T@TM& ze-`Wi5ftbKPTMfSx3d1Te|U6sSl0i~4|nT7xAJ@?`v2$bU>aME2%usOv`q$s{*@^B3<$rI!HDDgJ0TT5)g_~B|5FTnPa(`Jw3bnRl4rd6I z3@i}|-@H7h5e}xS3RnruZOEIZS*O&}gQxt}o6C)mK7(^>v_I^Wn_7wZ8`)O2F7fT( zE7JTH)oRDUz6a`cRa9!#>>YAhU%tH_s}+pfZG!2@o zY_|Yzhvydhymrq+SpVpYp zyOi2mDYd3_{>rmzcfCaKR-eV|KQR}0t>ga}tp7Yb>K*mU=Re5eyY-)2c)pVLpJ!4? z!Rt=~5v^Dn&JZZ!cB-wY!B7rC50?e^vot8b9iyP>cBb!pTZ(A5&WaQ>SIjjd*P_DP zq}99J$}B@Jr`n1XbIhAVhdOf2ExCkGUk_*Il*r=ZYqwp<={9Km4syU+N-oWH;!DX$ zR%t~Ev3Hm+l8-s%mf%nwl$o-zsPHyj>VmEmC;XAeY?_f z>~!jFbUYeD=HT!D$S?Rnl@ zrJKJqjv+R|0eVfA4TcL9H_ST+^qnzqB^>UGi@#zfQWzPem*Qio>Sj4v1b$b%TosGE z;^qg)=eM?_sPeGDexH!cXnCu zdmTSD$b!#f>@E?0ANAgXMEE?0?sDM`bK&!dxJ!rM|8)2~{_Qg2_tI7^$cWG7=q@R~ zd{TTKL3era`#o0X>-81)D zy#F^wQY;2*>;Rs>|F_pa?03uezw~zZzij9EO7{Q0l|uUFWy5)8E7B_}SzCSnmbaOu zwqubjMPB~!>YPzY<>iQz*V`PKIyun$OtBx&Pr?ae0&^6j#z$sbx|M2gl6oc3_nU_2 z2(hI}Co64?V*QSR*oaV-Q$kkdQR5cxhBc=&j#Gj~)7xAO+F7*?3UmhZ9+T_r{3Hw+ z;{2S_XgQJr+#@}W2%ft?2Q9rJVrEbb9wPe#pG{m$mDf^thfOsSQJ<-p`WFVe=lduG#lokIf~ zjHFq|^=*GNEsM#WkEqLl!33=p6}TX7X)L)-Jgk9a7AmdhEEa)md>|FU-{nAB9g{mB zNLOP>s2cyPa@m2faTYtU?~=bOqH*WUZ9FrwOZ)B8e)q-nG)nt5l;d6IZ!?*{70A6y z{@pigFgN+vki)zD-#z8+jQn3yw(e4Z_lA$NQ-IBxxyu6HYu?Vv0xr$qT_SMRMBvh- z-sJ-C>$qBw3v9^gT{>``bYN2=?=ph-emKp~2sUK&E-846{JrZ1l3)3=c>V7rzJUy_ zvHfe|{@=s?^YZ%NZtvM{{qHuOuVnqN7Se{3I=b*FSvh13hy}7R^*q1mc5L2E;>@sb zUjcpYdRRS}XR-eO7mOeY>Fw?R?HwLHt?d6jdb-p9+jzbb{r{g@NWnSfV#Ltp|9k_M zy=>UZ`HDIZ1~}9({E*I=1)fo6J62#x63ws;hDs;0Cl7{FcRk4N@l&V&CosaHx>}ES z{vJTiAqg2=-2g1m|NZBO{j&Z)JnHTA|2Ceo{(s3R3^k`$elw5V}2}EP8;xa5R4%cpbcJ98X-tP8@x{>vM}<&hcOak z#K5U-3t$dXjzR!=UY9aJsPMrnG=ym+jV36>)7!HiS4 zFAF81JRa+rT>7@M)3eb2$B;^ z6uVb10Ykr~n4u6Pkn{>6($&QF%{F9s#BsS>(a-i#m>37zQLv#kk_@_(ibBC^mwZS>+-O z$bvBzC=e+_4H0u{RG_6|e9q7ie`*Fx+6Y;v3`c$b8BH%J73YSg5@KfIxzC(WUZLeW zK+E^zzi&s#u!|nBrEmOG^IbVa5{l2d^r?vIdAzU2>$#;T7-qh1&Kn}Nzz zsC7-XCbcc&p;GeuO3RnV&qSiZ&X~E}PwGVm3FJ z;MlY?(FFaKG8`6g4aC*58%+V-LTzhx^j}&i(m^%|7UI* zxV`m%htHl@?*Hx{?&klt^4zoh-)(!yMwqwdA*-uB2AfmP4bWfB9vi@4g@5c}b6{NVIKvO!~f^|H{zl&$l%)mvNh%p|_gbw54#Sq@H}n6LFmKEIn_m9UH=9#f z3sGN9Ybmf_h2N)ovZM^G<@417THoVSU>}CRx1@9O5$ASk)=F%Vj$H-PE&HjCV%(Io+PGu4 zrfl+}zhtY3nv&y#834#xaX+e^o~6vWr9R#TSDk^G8Do6+noDIa$+^g7zd zh4VECd2P2gsS;hfFRdQSa2El)1tsY=nXIcPYggnyd?A|IwS|H-Lr{{kLMTYd+>&>a z4_FxgGZf;LZ~oQK!u|if=au=N-fsWjR-XHQ{>!Q!yB6EU+D@0-fS+CuXl;9>!QN-@ zJkdL{5-7%*`O#!plKRSPRlsi9vZz)!W>m_3;8`c;Fke@4`M8)Fr(+ac^DGOdIG}o> zpnl6Ofw|sXDj*3V!~fEX9PCfbSwR2s0`!hrOY$azhC+X0&-__;l+*$(#0XEEA}6UB z7qOf3+=yD%Gc{T z01NDYuiLNe|9|#uXaBeIe699hiERV>ugh(~{?`Lq+x}~?+qM69Et9)vd(T4s@9vyk z(FiQi|4)0>^WUED=6|>I+<*O_9SLJjMv>)I=6HZ=kATsK7N{yp@10UI>~^I)w_o1+ z?#ZCV7gVclZ`SEAcFViX*tEM{yYYTTbG^+r*UOvR)aLemb$mrFrRw_Asv5&GXF%eH zVz$@y^Ws-yqyt7lZM>*@Kt=`@CQcmbPhlJtj={+f8+kP2#GO3qn|b0+eZw4#5J3zI z6n2(4fJZTHF#@`n>7BtQgaX#Lv0xQI1HL^rA1d3oT{vIp`wZ|Wv>C)MfPCli<*A|ywMF@nW1BP32!#t;$N)U@YSriCF1 zGtFW&N@;OY*4P~Ssft(hHJSVhnRD#cOl0!h6S&GF&_EZ_0)PCGd?fbVn{W6>QlFvH z2i4;f>0}&?3f3)Yny8Qd4^dO|Q zc??dK)Pi46FF}YIf3)Y1u;}Q2bT=OD`GbG4j{YZmH6C@;f3p{SLOKPI0~lPVi3&{l zqrLBZev`<52Jl+`BVzgM|F3KO3K^y;2WPKdOAHc5|A_+eXwSzXf*n(w(SJVL^Cvu@ zAu=tUFoB0K5TNh(|0HAM$6zc(!jC(h5f0Kj@Kr zD!(hQZh8Lal<%L`Rec4yEGo4td)=oL?+53L}W67j4L1(H;H-P ztDf!EVY`21dL@CxQt6#WG!2Q?T<1SJx2M=r1l`!Z=t@j*-+o_9)SM=Nh(9hez$uxvy!xV$DPj2 z&5aLLGd^XbPNbXSojqCc>h;CjOK|e;6*ztW?$z1V+52~w;D`4Y;FrtS2jJrM`NjKJ zznsd~2ddPov&*ZCvzNcfHwr*cE$6@l>%e=@VB?t{d4P{$6oD8)okkFd#atc2{-hHOn1hf8 zX^e;{<3(8ou^>y*(;I>qP_vyv>L8ekF;!~^z+h_N)YVW~49vlZL86j0BIm4w02;vv zyjGwqNTft|(4~=1ReFQifwWsFQ0sp% z(SIK(oeWd1GFt|U{-h|tKnw{SA;~=1E>DB8LF^z~qcfOl?4g3~QsxFrX`&45W8Bj0 z;bWXgNJBgnQ|b8z67>Gl?l&#foHSCJ@D@-i)UpxD13rcfaSIW*zyJ|6!~up;5xRqC z&ho#|)KlkY%fFb{a=8wPqR9k@sf5LVD<1{``h-}3xr!DLi!oRBOUs!a1d1&cQM;rm z3y>#=S6r4f866a(+-`rM?7E^9ZYaA}7%M#_B`qHUnAmP)13;6`bSs7-0&oIx1P75F|BhZd zklIuVU;vFM!Avh$?MA4;0m{^yNw}%Ruv9BT%`1jB_a(74Aod{v=o5^SNTsS1Mkm-* zlqFBp`PBFm7@&yWv~nuELJUu|t0)P=y|M(zHtK0$dT$_U8d$^!kW1zfH55bHhLnCr zW38)XQ;J=3EZmH7Fm{vy3e^qVFaiusuwtc@VnT%(CjdooK$-nTnPsy(nhY>$n_0jj!c+ zc?@Jj)@d&zpk0q?Y-xsv1XkdQlHt&JA{G+Wv{AJvn~D5^Gbn`A`jo&ZvTB>BgBS~= zJgncLq)TD0&@)3pHKg=-#jUVhR_1Q5wQwC3sg+gpQr-t>45J~S!`aSDGi$G=*mR#f z154ZcOfAzPKoJTAqXY*Bk_&1Rwj5DR)+5UKNQt37kfXpQI?4$p=_GhQSQP#F!CX_6 z=`OboN*tU(3~?kYN0Q9OA!%~Y&M`Qq0Buez*1K$qP`D)lx~%5Hea@5Ju7gTYU65T zwKkY>hMB9C5e&w_ArO!%WH8lUobn6)LQ?>xhnFCc!pMr>4P{YygQc%QC}}Isb39Q$ z+rb#Jkqn&Z6h>m&9x{Xu0A>tLXdo4N#hRP=Pc~?yEp#B=!9>b&MbqW#JV^%;4x*_P z)Fgt_gZxc`m^QUsy)ll38@IV`ex{3+vs`Jh#+)nNq8W7PFz6ggrTZ0dXCHkEP$JZ3 z31J7LLXhi#s09+;SBHBsyhaCL3@1o=c@`lRN7La@r@c6eq670^94C|s&6rFN7)RN7 zg-XrXo~d;Qibu9pm?V)5Hz|pxn#xjl8PtLZ;+UJVPUi+w4aB8xrZ))+5a*C#H9Ch3 zlaY;R5Vp3@9r*ja1zNueglnv=pvK87B4?Vo(fd}kt@FXz zQ1U;Eg}A^%%5=sQfz7N796|Y6DLE6k@8ysZc(yP>kPi0R*$00<&@!&59| zS0gmiM!+nQ_>lY8QqdK);yeYXY=TCdn@~H46XeX9+HP5X#L80@W29ZNq9j_E$p)il zq}V_sA7jSkS+7c42RTF~_pGcyZXGtYRL2NkMqSKRoEU0VaO8sv$5atWEd~O?HrnLW&@{XvN4Zdl=Fv zqBq*UTitcMm&H{r-P4o{Fp~I6^r+c=72pITskB_zH;WGCQ|TyF_Msd}{8^b%+vdP& zQzve6S6aqVGJe-d9VSJH(HIjcCpvoMPV-X5Wg;zM25OEZG;59`#EUHlPRk4lh{=KV zo1G9|MF(VB>73JW)?h9W2Xchv*73kd_kmQ4A(DR6f#Xal5f%AxGkw!3h#Gv#Dz)gj zY3*rYDC9z_9NGji*-c4KJ>t~*r$SGvrn*S9uqBmN#{X>d8U)_E_g819uRS2pC%r&e z4m;C^bh({&+|lKzfSQp~p{(MU1ImV;5HJKo6=UW?hib_xl@i1Rx#TxWO=$+*5!Ho* zCUkYc)Kj>Yu1eUT01<**hEr~q-Y%5OMr#tuAo$p#2`!E}t#b+$q>9hQ;m@uzF9?}C zu8RpMfQPxBktTDLTfi!O$_}bjhSt|}vRo!MsG-uZG*XlUF+of-ON=oK+p?3>j5ma` zSO(1Msxrv*QcJarjugbuP{rZ5avpRjohA8TIaj` zR)GQ1egI3$@}~(iYu=)kM0r%9+*XyW*A74_@#U~W0x|t?QKk%pSbD7mFSo{n&r^Ff zQ$`w$Ggm~1HP{^F!$uvmN~SYH5jQ)R4J8FnHtl5das(=~RRt@YdEEhxwJR;oE2g1ONrVF|!(Ro_nIOsX8`H8E=_Iq9G}g@2 zRqpA_7R!ko?dlEO?DI0AnQ^lenvTF|5ZZMO?d+qj|Beb-DVx1f_GLhIP$q}%NQHOO zj40H2njpqei1b8|90m?cOhekc&YKscr;uFglb_3Fh3~+ zMuyGu4kNS{g- zO_p!Q8q}BoO{wQTc!jwNoe-0yK0qevGR+1-hU#Fd16UP#%MdG91B#0(c*(P12RXyc z*ylN_`)WxH494XU)h&$$FEY0UsG9NfPA0`sw{ISK!0R#l^|H ztFzaa;QfU=E&u)paPsai;ODbSRo9p+&CY3nvoKjJbu-VZva#+& zYc-hFviH3Y-ee?|mEK^zdTZ)~GiiANnn>A|cxV`ef=DGh#TZdGby6*MCQDEz+>`-9 zqX>@>2~g`Go9#X*q;j*&&q8_M*Ny@QA&T%oIdlrS5u==E^A@&A0bn4wnjNnnA6k1B z%m-y)U|AMn)v(D3DAvLlj*2;aS=%lN$QK9j1O+%xvSAY7P&&4HDnU9hI;V?aWPw@@ z9gLwQ5n=!`J!dYhcxJ148i{hCtEib~IwsX`Ffq(@^s1XN*q=KmZn2Wxj;I#c5vAb` zj@;bgHQ<6K2^^sVWC7jcmKl^_9)V=25YJ#@o}w+@sXN(a51 zh%+#iK)Mr&PJc(;_N~YhFu5nyXQTukv*AS(IF(=b0i$3`|Z~#!Psq^|KuCdb}&z3^Uqn_%5)iX+6-=>aC1JIEt>watnHM1qKNt@H;B2G>Y%;QjS)ULK@GFtFBc zYJ~~w&EzWTb0TRU?7yPq+ibmnGe#}&|Iz{~T32BzAJa4n)gCE}hlvgxv+c~y%CW+y zM8HqkM5qetH3B~PfB=j*1q|uZCQoX$xGJmVhU*2%I_y$zW@3%8omw5Be94NMA+?xr zby2?B^rbc&j*us9MRDfSEPhdkpFobY`FKM)JMWsMXYwS6x;bKEHDx}T_}A%lI{h2? zD=|AEOS7zhQ^k#tgig#<6rTfkK`7Xl1+q1ltv^c;HXf0RK$|aCMFD3sxgzO z%*An{emYRuGFV92SwV)viu3&vG>%7`8fA6jrH}9T>Prm;D z;`Pa^x34$8`Dfw!|6aFx{#XC#>2Cf1R-VV;Qa~n9FeW&Fb_?7aJYbMbf!bO2Xz$V9 z3Ha+zD2j_8{`+VF9X}~*zCOF`oNEiLP*}e8ymT4(PGh#GN?8+cYKtxA4 z00Sg$q=#R?M_2aECZ4M|e|~i#|Nh56{xOAd^k^?c2_hjP0Y>(y1ZlO7^W8&w^R!uP zcMQDmyzD4m%CVqqdYtXO<4)7Q*@%Z}2PO$uZJMSBkdGhjJpr;uAj4n^(jnsNYEg9?qOm>ftnf(tSQK?C8!ZtKP5lz%?BuyQYW>5^Ou%u-g%{V73#wAN=NNrig%Xzz1-`Dc|nOMsGCfq&$C>D>K$K9=N+K0qFyrz1@K ze9zlIWFIe(NLj^8c6P?8(X4m^6p%M2vfW=-L=G&AUlG;} zrmlkIiCNOB&kv^&4yNnSu@2m(P<@5CFe{NR(g>9)x*VcqV4I`p6^c-d1S`>TN&Ips z%@NZ|CO}NIjketBnk7JK*4FV=lJu>yKjm@Un6EBh>PPT=zB=aZM<~z@oPv|{vsF2K zUwM3oTqa1|PyCkSNBbYKo`CCfVE+aBpQ8(wj znK6Rr@)o={d$rWu8Y)Br=4hz=w56H$(rNJp^*O-LI zR*WC*#Yn&q3aCOA9jJ`-x3)g|z|4gwFerUeuO99Bzz2SQ%#v&(k2Xx+MgGc@dH*$_ z$@I_qOiwqolBL$n;XT@0H-q/main/schema.sql Schema +# sql//main/queries.conf Authorisation and Accounting queries +# +# Where "DB" is mysql, mssql, oracle, or postgresql. +# +# The name used to query SQL is sql_user_name, which is set in the file +# +# raddb/mods-config/sql/main/${dialect}/queries.conf +# +# If you are using realms, that configuration should be changed to use +# the Stripped-User-Name attribute. See the comments around sql_user_name +# for more information. +# + +sql { + # + # The dialect of SQL being used. + # + # Allowed dialects are: + # + # mssql + # mysql + # oracle + # postgresql + # sqlite + # mongo + # +# dialect = "sqlite" + dialect = $ENV{FREERADIUS_MODS_SQL_DIALECT} + + # + # The driver module used to execute the queries. Since we + # don't know which SQL drivers are being used, the default is + # "rlm_sql_null", which just logs the queries to disk via the + # "logfile" directive, below. + # + # In order to talk to a real database, delete the next line, + # and uncomment the one after it. + # + # If the dialect is "mssql", then the driver should be set to + # one of the following values, depending on your system: + # + # rlm_sql_db2 + # rlm_sql_firebird + # rlm_sql_freetds + # rlm_sql_iodbc + # rlm_sql_unixodbc + # +# driver = "rlm_sql_null" + driver = "rlm_sql_${dialect}" + + # + # Driver-specific subsections. They will only be loaded and + # used if "driver" is something other than "rlm_sql_null". + # When a real driver is used, the relevant driver + # configuration section is loaded, and all other driver + # configuration sections are ignored. + # + sqlite { + # Path to the sqlite database + filename = $ENV{FREERADIUS_MODS_SQL_SQLITE_FILENAME} + + # How long to wait for write locks on the database to be released (in ms) before giving up. + busy_timeout = $ENV{FREERADIUS_MODS_SQL_SQLITE_BUSY_TIMEOUT} + + # If the file above does not exist and bootstrap is set + # a new database file will be created, and the SQL statements + # contained within the bootstrap file will be executed. + bootstrap = "${modconfdir}/${..:name}/main/sqlite/schema.sql" + } + + mysql { + # If any of the files below are set, TLS encryption is enabled + tls { +# ca_file = $ENV{FREERADIUS_MODS_SQL_TLS_CACERT} +# ca_path = "/startechnica/freeradius/certs-sql/" +# certificate_file = $ENV{FREERADIUS_MODS_SQL_TLS_CERTIFICATE} +# private_key_file = $ENV{FREERADIUS_MODS_SQL_TLS_PRIVATEKEY} +# cipher = "DHE-RSA-AES256-SHA:AES128-SHA" +# cipher = $ENV{FREERADIUS_MODS_SQL_TLS_CIPHER} + + tls_required = $ENV{FREERADIUS_MODS_SQL_TLS_ENABLE} + tls_check_cert = no + tls_check_cert_cn = no + } + + # If yes, (or auto and libmysqlclient reports warnings are + # available), will retrieve and log additional warnings from + # the server if an error has occured. Defaults to 'auto' + warnings = auto + } + + postgresql { + + # unlike MySQL, which has a tls{} connection configuration, postgresql + # uses its connection parameters - see the radius_db option below in + # this file + + # Send application_name to the postgres server + # Only supported in PG 9.0 and greater. Defaults to no. + send_application_name = yes + } + + # + # Configuration for Mongo. + # + # Note that the Mongo driver is experimental. The FreeRADIUS developers + # are unable to help with the syntax of the Mongo queries. Please see + # the Mongo documentation for that syntax. + # + # The Mongo driver supports only the following methods: + # + # aggregate + # findAndModify + # findOne + # insert + # + # For examples, see the query files: + # + # raddb/mods-config/sql/main/mongo/queries.conf + # raddb/mods-config/sql/main/ippool/queries.conf + # + # In order to use findAndModify with an aggretation pipleline, make + # sure that you are running MongoDB version 4.2 or greater. FreeRADIUS + # assumes that the paramaters passed to the methods are supported by the + # version of MongoDB which it is connected to. + # + mongo { + # + # The application name to use. + # + appname = "freeradius" + + # + # The TLS parameters here map directly to the Mongo TLS configuration + # + tls { + certificate_file = $ENV{FREERADIUS_MODS_SQL_TLS_CERTIFICATE} + certificate_password = $ENV{FREERADIUS_MODS_SQL_TLS_PRIVATEKEY} + ca_file = $ENV{FREERADIUS_MODS_SQL_TLS_CACERT} + ca_dir = /startechnica/freeradius/certs-sql/ + # crl_file = /path/to/file + weak_cert_validation = false + allow_invalid_hostname = false + } + } + + # Connection info: + # + server = $ENV{FREERADIUS_MODS_SQL_SERVER} + port = $ENV{FREERADIUS_MODS_SQL_PORT} + login = $ENV{FREERADIUS_MODS_SQL_LOGIN} + password = $ENV{FREERADIUS_MODS_SQL_PASSWORD} + + # Connection info for Mongo + # Authentication Without SSL + # server = "mongodb://USER:PASSWORD@192.16.0.2:PORT/DATABASE?authSource=admin&ssl=false" + + # Authentication With SSL + # server = "mongodb://USER:PASSWORD@192.16.0.2:PORT/DATABASE?authSource=admin&ssl=true" + + # Authentication with Certificate + # Use this command for retrieve Derived username: + # openssl x509 -in mycert.pem -inform PEM -subject -nameopt RFC2253 + # server = mongodb://@192.168.0.2:PORT/DATABASE?authSource=$external&ssl=true&authMechanism=MONGODB-X509 + + # Database table configuration for everything except Oracle + radius_db = $ENV{FREERADIUS_MODS_SQL_DB} + + # If you are using Oracle then use this instead +# radius_db = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SID=your_sid)))" + + # If you're using postgresql this can also be used instead of the connection info parameters +# radius_db = "dbname=$ENV{FREERADIUS_MODS_SQL_DB} host=$ENV{FREERADIUS_MODS_SQL_SERVER} port=$ENV{FREERADIUS_MODS_SQL_PORT} user=$ENV{FREERADIUS_MODS_SQL_LOGIN} password=$ENV{FREERADIUS_MODS_SQL_PASSWORD}" + + # Postgreql doesn't take tls{} options in its module config like mysql does - if you want to + # use SSL connections then use this form of connection info parameter +# radius_db = "host=localhost port=5432 dbname=radius user=radius password=raddpass sslmode=verify-full sslcert=/etc/ssl/client.crt sslkey=/etc/ssl/client.key sslrootcert=/etc/ssl/ca.crt" + + # If you want both stop and start records logged to the + # same SQL table, leave this as is. If you want them in + # different tables, put the start table in acct_table1 + # and stop table in acct_table2 + acct_table1 = $ENV{FREERADIUS_MODS_SQL_TABLE_ACCT1} + acct_table2 = $ENV{FREERADIUS_MODS_SQL_TABLE_ACCT2} + + # Allow for storing data after authentication + postauth_table = $ENV{FREERADIUS_MODS_SQL_TABLE_POSTAUTH} + + # Tables containing 'check' items + authcheck_table = $ENV{FREERADIUS_MODS_SQL_TABLE_AUTHCHECK} + groupcheck_table = $ENV{FREERADIUS_MODS_SQL_TABLE_GROUPCHECK} + + # Tables containing 'reply' items + authreply_table = $ENV{FREERADIUS_MODS_SQL_TABLE_AUTHREPLY} + groupreply_table = $ENV{FREERADIUS_MODS_SQL_TABLE_GROUPREPLY} + + # Table to keep group info + usergroup_table = $ENV{FREERADIUS_MODS_SQL_TABLE_USERGROUP} + + # If set to 'yes' (default) we read the group tables unless Fall-Through = no in the reply table. + # If set to 'no' we do not read the group tables unless Fall-Through = yes in the reply table. +# read_groups = yes + + # If set to 'yes' (default) we read profiles unless Fall-Through = no in the groupreply table. + # If set to 'no' we do not read profiles unless Fall-Through = yes in the groupreply table. +# read_profiles = yes + + # Remove stale session if checkrad does not see a double login + delete_stale_sessions = yes + + # Write SQL queries to a logfile. This is potentially useful for tracing + # issues with authorization queries. See also "logfile" directives in + # mods-config/sql/main/*/queries.conf. You can enable per-section logging + # by enabling "logfile" there, or global logging by enabling "logfile" here. + # + # Per-section logging can be disabled by setting "logfile = ''" +# logfile = ${logdir}/sqllog.sql + + # Set the maximum query duration and connection timeout + # for rlm_sql_mysql. +# query_timeout = 5 + + # As of version 3.0, the "pool" section has replaced the + # following configuration items: + # + # num_sql_socks + # connect_failure_retry_delay + # lifetime + # max_queries + + # + # The connection pool is new for 3.0, and will be used in many + # modules, for all kinds of connection-related activity. + # + # When the server is not threaded, the connection pool + # limits are ignored, and only one connection is used. + # + # If you want to have multiple SQL modules re-use the same + # connection pool, use "pool = name" instead of a "pool" + # section. e.g. + # + # sql sql1 { + # ... + # pool { + # ... + # } + # } + # + # # sql2 will use the connection pool from sql1 + # sql sql2 { + # ... + # pool = sql1 + # } + # + pool { + # Connections to create during module instantiation. + # If the server cannot create specified number of + # connections during instantiation it will exit. + # Set to 0 to allow the server to start without the database being available. + start = ${thread[pool].start_servers} + + # Minimum number of connections to keep open + min = ${thread[pool].min_spare_servers} + + # Maximum number of connections + # + # If these connections are all in use and a new one + # is requested, the request will NOT get a connection. + # + # Setting 'max' to LESS than the number of threads means + # that some threads may starve, and you will see errors + # like 'No connections available and at max connection limit' + # + # Setting 'max' to MORE than the number of threads means + # that there are more connections than necessary. + max = ${thread[pool].max_servers} + + # Spare connections to be left idle + # + # NOTE: Idle connections WILL be closed if "idle_timeout" + # is set. This should be less than or equal to "max" above. + spare = ${thread[pool].max_spare_servers} + + # Number of uses before the connection is closed + # + # 0 means "infinite" + uses = 0 + + # The number of seconds to wait after the server tries + # to open a connection, and fails. During this time, + # no new connections will be opened. + retry_delay = 30 + + # The lifetime (in seconds) of the connection + lifetime = 0 + + # idle timeout (in seconds). A connection which is + # unused for this length of time will be closed. + idle_timeout = 60 + + # NOTE: All configuration settings are enforced. If a + # connection is closed because of "idle_timeout", + # "uses", or "lifetime", then the total number of + # connections MAY fall below "min". When that + # happens, it will open a new connection. It will + # also log a WARNING message. + # + # The solution is to either lower the "min" connections, + # or increase lifetime/idle_timeout. + } + + # Set to 'yes' to read radius clients from the database ('nas' table) + # Clients will ONLY be read on server startup. + # + # A client can be link to a virtual server via the SQL + # module. This link is done via the following process: + # + # If there is no listener in a virtual server, SQL clients + # are added to the global list for that virtual server. + # + # If there is a listener, and the first listener does not + # have a "clients=..." configuration item, SQL clients are + # added to the global list. + # + # If there is a listener, and the first one does have a + # "clients=..." configuration item, SQL clients are added to + # that list. The client { ...} ` configured in that list are + # also added for that listener. + # + # The only issue is if you have multiple listeners in a + # virtual server, each with a different client list, then + # the SQL clients are added only to the first listener. + # + read_clients = $ENV{FREERADIUS_MODS_SQL_READ_CLIENTS} + + # Table to keep radius client info + client_table = $ENV{FREERADIUS_MODS_SQL_TABLE_CLIENT} + + # + # The group attribute specific to this instance of rlm_sql + # + + # This entry should be used for additional instances (sql foo {}) + # of the SQL module. +# group_attribute = "${.:instance}-SQL-Group" + + # This entry should be used for the default instance (sql {}) + # of the SQL module. + group_attribute = $ENV{FREERADIUS_MODS_SQL_GROUP_ATTRIBUTE} + + # Read database-specific queries + $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf +} \ No newline at end of file diff --git a/files/schema/mysql.sql b/files/schema/mysql.sql new file mode 100644 index 0000000..ef78b2b --- /dev/null +++ b/files/schema/mysql.sql @@ -0,0 +1,165 @@ +########################################################################### +# $Id: 41fcccad1c012226d12cc721518fe91e311e55e2 $ # +# # +# schema.sql rlm_sql - FreeRADIUS SQL Module # +# # +# Database schema for MySQL rlm_sql module # +# # +# To load: # +# mysql -uroot -prootpass radius < schema.sql # +# # +# Mike Machado # +########################################################################### + +# +# Table structure for table 'radacct' +# +CREATE TABLE IF NOT EXISTS radacct ( + radacctid bigint(21) NOT NULL auto_increment, + acctsessionid varchar(64) NOT NULL default '', + acctuniqueid varchar(32) NOT NULL default '', + username varchar(64) NOT NULL default '', + realm varchar(64) default '', + nasipaddress varchar(15) NOT NULL default '', + nasportid varchar(32) default NULL, + nasporttype varchar(32) default NULL, + acctstarttime datetime NULL default NULL, + acctupdatetime datetime NULL default NULL, + acctstoptime datetime NULL default NULL, + acctinterval int(12) default NULL, + acctsessiontime int(12) unsigned default NULL, + acctauthentic varchar(32) default NULL, + connectinfo_start varchar(128) default NULL, + connectinfo_stop varchar(128) default NULL, + acctinputoctets bigint(20) default NULL, + acctoutputoctets bigint(20) default NULL, + calledstationid varchar(50) NOT NULL default '', + callingstationid varchar(50) NOT NULL default '', + acctterminatecause varchar(32) NOT NULL default '', + servicetype varchar(32) default NULL, + framedprotocol varchar(32) default NULL, + framedipaddress varchar(15) NOT NULL default '', + framedipv6address varchar(45) NOT NULL default '', + framedipv6prefix varchar(45) NOT NULL default '', + framedinterfaceid varchar(44) NOT NULL default '', + delegatedipv6prefix varchar(45) NOT NULL default '', + class varchar(64) default NULL, + PRIMARY KEY (radacctid), + UNIQUE KEY acctuniqueid (acctuniqueid), + KEY username (username), + KEY framedipaddress (framedipaddress), + KEY framedipv6address (framedipv6address), + KEY framedipv6prefix (framedipv6prefix), + KEY framedinterfaceid (framedinterfaceid), + KEY delegatedipv6prefix (delegatedipv6prefix), + KEY acctsessionid (acctsessionid), + KEY acctsessiontime (acctsessiontime), + KEY acctstarttime (acctstarttime), + KEY acctinterval (acctinterval), + KEY acctstoptime (acctstoptime), + KEY nasipaddress (nasipaddress), + KEY class (class) +) ENGINE = INNODB; + +# +# Table structure for table 'radcheck' +# +CREATE TABLE IF NOT EXISTS radcheck ( + id int(11) unsigned NOT NULL auto_increment, + username varchar(64) NOT NULL default '', + attribute varchar(64) NOT NULL default '', + op char(2) NOT NULL DEFAULT '==', + value varchar(253) NOT NULL default '', + PRIMARY KEY (id), + KEY username (username(32)) +) ENGINE = INNODB; + +# +# Table structure for table 'radgroupcheck' +# +CREATE TABLE IF NOT EXISTS radgroupcheck ( + id int(11) unsigned NOT NULL auto_increment, + groupname varchar(64) NOT NULL default '', + attribute varchar(64) NOT NULL default '', + op char(2) NOT NULL DEFAULT '==', + value varchar(253) NOT NULL default '', + PRIMARY KEY (id), + KEY groupname (groupname(32)) +) ENGINE = INNODB; + +# +# Table structure for table 'radgroupreply' +# +CREATE TABLE IF NOT EXISTS radgroupreply ( + id int(11) unsigned NOT NULL auto_increment, + groupname varchar(64) NOT NULL default '', + attribute varchar(64) NOT NULL default '', + op char(2) NOT NULL DEFAULT '=', + value varchar(253) NOT NULL default '', + PRIMARY KEY (id), + KEY groupname (groupname(32)) +) ENGINE = INNODB; + +# +# Table structure for table 'radreply' +# +CREATE TABLE IF NOT EXISTS radreply ( + id int(11) unsigned NOT NULL auto_increment, + username varchar(64) NOT NULL default '', + attribute varchar(64) NOT NULL default '', + op char(2) NOT NULL DEFAULT '=', + value varchar(253) NOT NULL default '', + PRIMARY KEY (id), + KEY username (username(32)) +) ENGINE = INNODB; + + +# +# Table structure for table 'radusergroup' +# +CREATE TABLE IF NOT EXISTS `radusergroup` ( + id int(11) unsigned NOT NULL auto_increment, + username varchar(64) NOT NULL default '', + groupname varchar(64) NOT NULL default '', + priority int(11) NOT NULL default '1', + PRIMARY KEY (id), + KEY username (username(32)) +) ENGINE = INNODB; + +# +# Table structure for table 'radpostauth' +# +# Note: MySQL versions since 5.6.4 support fractional precision timestamps +# which we use here. Replace the authdate definition with the following +# if your software is too old: +# +# authdate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +# +CREATE TABLE IF NOT EXISTS radpostauth ( + id int(11) NOT NULL auto_increment, + username varchar(64) NOT NULL default '', + pass varchar(64) NOT NULL default '', + reply varchar(32) NOT NULL default '', + authdate timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), + class varchar(64) default NULL, + PRIMARY KEY (id), + KEY username (username), + KEY class (class) +) ENGINE = INNODB; + +# +# Table structure for table 'nas' +# +CREATE TABLE IF NOT EXISTS nas ( + id int(10) NOT NULL auto_increment, + nasname varchar(128) NOT NULL, + shortname varchar(32), + type varchar(30) DEFAULT 'other', + ports int(5), + secret varchar(60) DEFAULT 'secret' NOT NULL, + server varchar(64), + community varchar(50), + description varchar(200) DEFAULT 'RADIUS Client', + PRIMARY KEY (id), + KEY nasname (nasname) +) ENGINE = INNODB; diff --git a/files/sites-available/coa b/files/sites-available/coa new file mode 100644 index 0000000..85849a8 --- /dev/null +++ b/files/sites-available/coa @@ -0,0 +1,41 @@ +# -*- text -*- +###################################################################### +# +# Sample virtual server for receiving a CoA or Disconnect-Request packet. +# + +# Listen on the CoA port. +# +# This uses the normal set of clients, with the same secret as for authentication and accounting. +# + +listen { + type = coa + # ipaddr = $ENV{FREERADIUS_SITES_COA_LISTEN} + ipaddr = * + port = $ENV{FREERADIUS_SITES_COA_PORT} + virtual_server = coa +} + +server coa { + # When a packet is received, it is processed through the recv-coa section. This applies to *both* CoA-Request and Disconnect-Request packets. + recv-coa { + # CoA && Disconnect packets can be proxied in the same way as authentication or accounting packets. + # Just set Proxy-To-Realm, or Home-Server-Pool, and the packets will be proxied. + + # Do proxying based on realms here. You don't need "IPASS" or "ntdomain", as the proxying is based on the Operator-Name attribute. It contains the realm, + # and ONLY the realm (prefixed by a '1') + suffix + + # Insert your own policies here. + ok + } + + # When a packet is sent, it is processed through the send-coa section. This applies to *both* CoA-Request and Disconnect-Request packets. + send-coa { + # Sample module. + ok + } + + # You can use pre-proxy and post-proxy sections here, too. They will be processed for sending && receiving proxy packets. +} \ No newline at end of file diff --git a/files/sites-available/default b/files/sites-available/default new file mode 100644 index 0000000..a5d37af --- /dev/null +++ b/files/sites-available/default @@ -0,0 +1,1072 @@ +###################################################################### +# +# As of 2.0.0, FreeRADIUS supports virtual hosts using the +# "server" section, and configuration directives. +# +# Virtual hosts should be put into the "sites-available" +# directory. Soft links should be created in the "sites-enabled" +# directory to these files. This is done in a normal installation. +# +# If you are using 802.1X (EAP) authentication, please see also +# the "inner-tunnel" virtual server. You will likely have to edit +# that, too, for authentication to work. +# +# $Id: 1926b7cd6e381cebfb809c7e89f8db0808124625 $ +# +###################################################################### +# +# Read "man radiusd" before editing this file. See the section +# titled DEBUGGING. It outlines a method where you can quickly +# obtain the configuration you want, without running into +# trouble. See also "man unlang", which documents the format +# of this file. +# +# This configuration is designed to work in the widest possible +# set of circumstances, with the widest possible number of +# authentication methods. This means that in general, you should +# need to make very few changes to this file. +# +# The best way to configure the server for your local system +# is to CAREFULLY edit this file. Most attempts to make large +# edits to this file will BREAK THE SERVER. Any edits should +# be small, and tested by running the server with "radiusd -X". +# Once the edits have been verified to work, save a copy of these +# configuration files somewhere. (e.g. as a "tar" file). Then, +# make more edits, and test, as above. +# +# There are many "commented out" references to modules such +# as ldap, sql, etc. These references serve as place-holders. +# If you need the functionality of that module, then configure +# it in radiusd.conf, and un-comment the references to it in +# this file. In most cases, those small changes will result +# in the server being able to connect to the DB, and to +# authenticate users. +# +###################################################################### + +server default { +# +# If you want the server to listen on additional addresses, or on +# additional ports, you can use multiple "listen" sections. +# +# Each section make the server listen for only one type of packet, +# therefore authentication and accounting have to be configured in +# different sections. +# +# The server ignore all "listen" section if you are using '-i' and '-p' +# on the command line. +# +listen { + # Type of packets to listen for. + # Allowed values are: + # auth listen for authentication packets + # acct listen for accounting packets + # auth+acct listen for both authentication and accounting packets + # proxy IP to use for sending proxied packets + # detail Read from the detail file. For examples, see + # raddb/sites-available/copy-acct-to-home-server + # status listen for Status-Server packets. For examples, + # see raddb/sites-available/status + # coa listen for CoA-Request and Disconnect-Request + # packets. For examples, see the file + # raddb/sites-available/coa + # + type = auth + + # Note: "type = proxy" lets you control the source IP used for + # proxying packets, with some limitations: + # + # * A proxy listener CANNOT be used in a virtual server section. + # * You should probably set "port = 0". + # * Any "clients" configuration will be ignored. + # + # See also proxy.conf, and the "src_ipaddr" configuration entry + # in the sample "home_server" section. When you specify the + # source IP address for packets sent to a home server, the + # proxy listeners are automatically created. + + # ipaddr/ipv4addr/ipv6addr - IP address on which to listen. + # If multiple ones are listed, only the first one will + # be used, and the others will be ignored. + # + # The configuration options accept the following syntax: + # + # ipv4addr - IPv4 address (e.g.192.0.2.3) + # - wildcard (i.e. *) + # - hostname (radius.example.com) + # Only the A record for the host name is used. + # If there is no A record, an error is returned, + # and the server fails to start. + # + # ipv6addr - IPv6 address (e.g. 2001:db8::1) + # - wildcard (i.e. *) + # - hostname (radius.example.com) + # Only the AAAA record for the host name is used. + # If there is no AAAA record, an error is returned, + # and the server fails to start. + # + # ipaddr - IPv4 address as above + # - IPv6 address as above + # - wildcard (i.e. *), which means IPv4 wildcard. + # - hostname + # If there is only one A or AAAA record returned + # for the host name, it is used. + # If multiple A or AAAA records are returned + # for the host name, only the first one is used. + # If both A and AAAA records are returned + # for the host name, only the A record is used. + # + # ipv4addr = * + # ipv6addr = * + ipaddr = * + + # Port on which to listen. + # Allowed values are: + # integer port number (1812) + # 0 means "use /etc/services for the proper port" + port = $ENV{FREERADIUS_SITES_DEFAULT_AUTH_PORT} + + # Some systems support binding to an interface, in addition + # to the IP address. This feature isn't strictly necessary, + # but for sites with many IP addresses on one interface, + # it's useful to say "listen on all addresses for eth0". + # + # If your system does not support this feature, you will + # get an error if you try to use it. + # +# interface = eth0 + + # Per-socket lists of clients. This is a very useful feature. + # + # The name here is a reference to a section elsewhere in + # radiusd.conf, or clients.conf. Having the name as + # a reference allows multiple sockets to use the same + # set of clients. + # + # If this configuration is used, then the global list of clients + # is IGNORED for this "listen" section. Take care configuring + # this feature, to ensure you don't accidentally disable a + # client you need. + # + # See clients.conf for the configuration of "per_socket_clients". + # +# clients = per_socket_clients + + # + # Set the default UDP receive buffer size. In most cases, + # the default values set by the kernel are fine. However, in + # some cases the NASes will send large packets, and many of + # them at a time. It is then possible to overflow the + # buffer, causing the kernel to drop packets before they + # reach FreeRADIUS. Increasing the size of the buffer will + # avoid these packet drops. + # +# recv_buff = 65536 + + # + # Connection limiting for sockets with "proto = tcp". + # + # This section is ignored for other kinds of sockets. + # + limit { + # + # Limit the number of simultaneous TCP connections to the socket + # + # The default is 16. + # Setting this to 0 means "no limit" + max_connections = 16 + + # The per-socket "max_requests" option does not exist. + + # + # The lifetime, in seconds, of a TCP connection. After + # this lifetime, the connection will be closed. + # + # Setting this to 0 means "forever". + lifetime = 0 + + # + # The idle timeout, in seconds, of a TCP connection. + # If no packets have been received over the connection for + # this time, the connection will be closed. + # + # Setting this to 0 means "no timeout". + # + # We STRONGLY RECOMMEND that you set an idle timeout. + # + idle_timeout = 30 + } +} + +# +# This second "listen" section is for listening on the accounting +# port, too. +# +listen { + ipaddr = * +# ipv6addr = :: + port = $ENV{FREERADIUS_SITES_DEFAULT_ACCT_PORT} + type = acct +# interface = eth0 +# clients = per_socket_clients + + limit { + # The number of packets received can be rate limited via the + # "max_pps" configuration item. When it is set, the server + # tracks the total number of packets received in the previous + # second. If the count is greater than "max_pps", then the + # new packet is silently discarded. This helps the server + # deal with overload situations. + # + # The packets/s counter is tracked in a sliding window. This + # means that the pps calculation is done for the second + # before the current packet was received. NOT for the current + # wall-clock second, and NOT for the previous wall-clock second. + # + # Useful values are 0 (no limit), or 100 to 10000. + # Values lower than 100 will likely cause the server to ignore + # normal traffic. Few systems are capable of handling more than + # 10K packets/s. + # + # It is most useful for accounting systems. Set it to 50% + # more than the normal accounting load, and you can be sure that + # the server will never get overloaded + # +# max_pps = 0 + + # Only for "proto = tcp". These are ignored for "udp" sockets. + # +# idle_timeout = 0 +# lifetime = 0 +# max_connections = 0 + } +} + +# IPv6 versions of the above - read their full config to understand options +listen { + type = auth + ipv6addr = :: # any. ::1 == localhost + port = $ENV{FREERADIUS_SITES_DEFAULT_AUTH_PORT} +# interface = eth0 +# clients = per_socket_clients + limit { + max_connections = 16 + lifetime = 0 + idle_timeout = 30 + } +} + +listen { + ipv6addr = :: + port = $ENV{FREERADIUS_SITES_DEFAULT_ACCT_PORT} + type = acct +# interface = eth0 +# clients = per_socket_clients + limit { + max_pps = 0 + idle_timeout = 0 + lifetime = 0 + max_connections = 0 + } +} + +# Authorization. First preprocess (hints and huntgroups files), +# then realms, and finally look in the "users" file. +# +# Any changes made here should also be made to the "inner-tunnel" +# virtual server. +# +# The order of the realm modules will determine the order that +# we try to find a matching realm. +# +# Make *sure* that 'preprocess' comes before any realm if you +# need to setup hints for the remote radius server +authorize { + # + # Take a User-Name, and perform some checks on it, for spaces and other + # invalid characters. If the User-Name appears invalid, reject the + # request. + # + # See policy.d/filter for the definition of the filter_username policy. + # + filter_username + + # + # Some broken equipment sends passwords with embedded zeros. + # i.e. the debug output will show + # + # User-Password = "password\000\000" + # + # This policy will fix it to just be "password". + # +# filter_password + + # + # The preprocess module takes care of sanitizing some bizarre + # attributes in the request, and turning them into attributes + # which are more standard. + # + # It takes care of processing the 'raddb/mods-config/preprocess/hints' + # and the 'raddb/mods-config/preprocess/huntgroups' files. + preprocess + + # If you intend to use CUI and you require that the Operator-Name + # be set for CUI generation and you want to generate CUI also + # for your local clients then uncomment the operator-name + # below and set the operator-name for your clients in clients.conf +# operator-name + + # + # If you want to generate CUI for some clients that do not + # send proper CUI requests, then uncomment the + # cui below and set "add_cui = yes" for these clients in clients.conf +# cui + + # + # If you want to have a log of authentication requests, + # un-comment the following line. +# auth_log + + # + # The chap module will set 'Auth-Type := CHAP' if we are + # handling a CHAP request and Auth-Type has not already been set + chap + + # + # If the users are logging in with an MS-CHAP-Challenge + # attribute for authentication, the mschap module will find + # the MS-CHAP-Challenge attribute, and add 'Auth-Type := MS-CHAP' + # to the request, which will cause the server to then use + # the mschap module for authentication. + mschap + + # + # If you have a Cisco SIP server authenticating against + # FreeRADIUS, uncomment the following line, and the 'digest' + # line in the 'authenticate' section. + digest + + # + # The WiMAX specification says that the Calling-Station-Id + # is 6 octets of the MAC. This definition conflicts with + # RFC 3580, and all common RADIUS practices. If you are using + # old style WiMAX (non LTE) the un-commenting the "wimax" module + # here means that it will fix the Calling-Station-Id attribute to + # the normal format as specified in RFC 3580 Section 3.21. + # + # If you are using WiMAX 2.1 (LTE) then un-commenting will allow + # the module to handle SQN resyncronisation. Prior to calling the + # module it is necessary to populate the following attributes + # with the relevant keys: + # control:WiMAX-SIM-Ki + # control:WiMAX-SIM-OPc + # + # If WiMAX-Re-synchronization-Info is found in the request then + # the module will attempt to extract SQN and store it in + # control:WiMAX-SIM-SQN. Also a copy of RAND is extracted to + # control:WiMAX-SIM-RAND. + # + # If the SIM cannot be authenticated using Ki and OPc then reject + # will be returned. +# wimax + + # + # Look for IPASS style 'realm/', and if not found, look for + # '@realm', and decide whether or not to proxy, based on + # that. +# IPASS + + # + # Look for realms in user@domain format + suffix +# ntdomain + + # + # This module takes care of EAP-MD5, EAP-TLS, and EAP-LEAP + # authentication. + # + # It also sets the EAP-Type attribute in the request + # attribute list to the EAP type from the packet. + # + # The EAP module returns "ok" or "updated" if it is not yet ready + # to authenticate the user. The configuration below checks for + # "ok", and stops processing the "authorize" section if so. + # + # Any LDAP and/or SQL servers will not be queried for the + # initial set of packets that go back and forth to set up + # TTLS or PEAP. + # + # The "updated" check is commented out for compatibility with + # previous versions of this configuration, but you may wish to + # uncomment it as well; this will further reduce the number of + # LDAP and/or SQL queries for TTLS or PEAP. + # + eap { + ok = return +# updated = return + } + + # Pull crypt'd passwords from /etc/passwd or /etc/shadow, using the system API's to get the password. If you want + # to read /etc/passwd or /etc/shadow directly, see the mods-available/passwd module. +# unix + + # Read the 'users' file. In v3, this is located in raddb/mods-config/files/authorize + files + + # Look in an SQL database. The schema of the database is meant to mirror the "users" file. + # + # See "Authorization Queries" in mods-available/sql + -sql + + # If you are using /etc/smbpasswd, and are also doing mschap authentication, the un-comment this line, and configure the 'smbpasswd' module. +# smbpasswd + + # The ldap module reads passwords from the LDAP database. + -ldap + + # Enforce daily limits on time spent logged in. +# daily + + # + expiration + logintime + + # + # If no other module has claimed responsibility for + # authentication, then try to use PAP. This allows the + # other modules listed above to add a "known good" password + # to the request, and to do nothing else. The PAP module + # will then see that password, and use it to do PAP + # authentication. + # + # This module should be listed last, so that the other modules + # get a chance to set Auth-Type for themselves. + # + pap + + # If "status_server = yes", then Status-Server messages are passed through the following section, and ONLY the following section. + # This permits you to do DB queries, for example. If the modules listed here return "fail", then NO response is sent. +# Autz-Type Status-Server { +# +# } + + # + # RADIUS/TLS (or RadSec) connections are processed through + # this section. See sites-available/tls, and the configuration + # item "check_client_connections" for more information. + # + # The request contains TLS client certificate attributes, + # and nothing else. The debug output will print which + # attributes are available on your system. + # + # If the section returns "ok" or "updated", then the + # connection is accepted. Otherwise the connection is + # terminated. + # + Autz-Type New-TLS-Connection { + ok + } +} + + +# Authentication. +# +# +# This section lists which modules are available for authentication. +# Note that it does NOT mean 'try each module in order'. It means +# that a module from the 'authorize' section adds a configuration +# attribute 'Auth-Type := FOO'. That authentication type is then +# used to pick the appropriate module from the list below. +# + +# In general, you SHOULD NOT set the Auth-Type attribute. The server +# will figure it out on its own, and will do the right thing. The +# most common side effect of erroneously setting the Auth-Type +# attribute is that one authentication method will work, but the +# others will not. +# +# The common reasons to set the Auth-Type attribute by hand +# is to either forcibly reject the user (Auth-Type := Reject), +# or to or forcibly accept the user (Auth-Type := Accept). +# +# Note that Auth-Type := Accept will NOT work with EAP. +# +# Please do not put "unlang" configurations into the "authenticate" +# section. Put them in the "post-auth" section instead. That's what +# the post-auth section is for. +# +authenticate { + # PAP authentication, when a back-end database listed in the 'authorize' section supplies a password. The password can be clear-text, or encrypted. + Auth-Type PAP { + pap + } + + # Most people want CHAP authentication + # A back-end database listed in the 'authorize' section MUST supply a CLEAR TEXT password. Encrypted passwords won't work. + Auth-Type CHAP { + chap + } + + # MSCHAP authentication. + Auth-Type MS-CHAP { + mschap + } + + # For old names, too. + mschap + + # If you have a Cisco SIP server authenticating against FreeRADIUS, uncomment the following line, and the 'digest' line in the 'authorize' section. + digest + + # Pluggable Authentication Modules. +# pam + + # Uncomment it if you want to use ldap for authentication + # + # Note that this means "check plain-text password against + # the ldap database", which means that EAP won't work, + # as it does not supply a plain-text password. + # + # We do NOT recommend using this. LDAP servers are databases. + # They are NOT authentication servers. FreeRADIUS is an + # authentication server, and knows what to do with authentication. + # LDAP servers do not. + # +# Auth-Type LDAP { +# ldap +# } + + # + # Allow EAP authentication. + eap + + # + # The older configurations sent a number of attributes in + # Access-Challenge packets, which wasn't strictly correct. + # If you want to filter out these attributes, uncomment + # the following lines. + # +# Auth-Type eap { +# eap { +# handled = 1 +# } +# if (handled && (Response-Packet-Type == Access-Challenge)) { +# attr_filter.access_challenge.post-auth +# handled # override the "updated" code from attr_filter +# } +# } +} + + +# Pre-accounting. Decide which accounting type to use. +# +preacct { + preprocess + + # Merge Acct-[Input|Output]-Gigawords and Acct-[Input-Output]-Octets into a single 64bit counter Acct-[Input|Output]-Octets64. +# acct_counters64 + + # Session start times are *implied* in RADIUS. + # The NAS never sends a "start time". Instead, it sends a start packet, *possibly* with an Acct-Delay-Time. + # The server is supposed to conclude that the start time was "Acct-Delay-Time" seconds in the past. + # + # The code below creates an explicit start time, which can then be used in other modules. It will be *mostly* correct. + # Any errors are due to the 1-second resolution of RADIUS, and the possibility that the time on the NAS may be off. + # + # The start time is: NOW - delay - session_length + +# update request { +# &FreeRADIUS-Acct-Session-Start-Time = "%{expr: %l - %{%{Acct-Session-Time}:-0} - %{%{Acct-Delay-Time}:-0}}" +# } + + # Ensure that we have a semi-unique identifier for every request, and many NAS boxes are broken. + acct_unique + + # Look for IPASS-style 'realm/', and if not found, look for '@realm', and decide whether or not to proxy, based on that. + # + # Accounting requests are generally proxied to the same + # home server as authentication requests. +# IPASS + suffix +# ntdomain + + # Read the 'acct_users' file + files +} + +# +# Accounting. Log the accounting data. +# +accounting { + # Update accounting packet by adding the CUI attribute recorded from the corresponding Access-Accept use it only if your NAS boxes do not support CUI themselves +# cui + # + # Create a 'detail'ed log of the packets. + # Note that accounting requests which are proxied are also logged in the detail file. + detail +# daily + + # Update the wtmp file + # + # If you don't use "radlast", you can delete this line. + unix + + # For Simultaneous-Use tracking. + # Due to packet losses in the network, the data here may be incorrect. There is little we can do about it. +# radutmp +# sradutmp + + # Return an address to the IP Pool when we see a stop record. + # Ensure that &control:Pool-Name is set to determine which pool of IPs are used. +# sqlippool + + # Log traffic to an SQL database. + # See "Accounting queries" in mods-available/sql + -sql + + # + # If you receive stop packets with zero session length, + # they will NOT be logged in the database. The SQL module + # will print a message (only in debugging mode), and will + # return "noop". + # + # You can ignore these packets by uncommenting the following + # three lines. Otherwise, the server will not respond to the + # accounting request, and the NAS will retransmit. + # +# if (noop) { +# ok +# } + + # Cisco VoIP specific bulk accounting +# pgsql-voip + + # For Exec-Program and Exec-Program-Wait + exec + + # Filter attributes from the accounting response. + attr_filter.accounting_response + + # + # See "Autz-Type Status-Server" for how this works. + # +# Acct-Type Status-Server { +# +# } +} + + +# Session database, used for checking Simultaneous-Use. Either the radutmp rlm_sql module can handle this. +# The rlm_sql module is *much* faster +session { +# radutmp + + # See "Simultaneous Use Checking Queries" in mods-available/sql + sql +} + + +# Post-Authentication +# Once we KNOW that the user has been authenticated, there are +# additional steps we can take. +post-auth { + # + # If you need to have a State attribute, you can + # add it here. e.g. for later CoA-Request with + # State, and Service-Type = Authorize-Only. + # +# if (!&reply:State) { +# update reply { +# State := "0x%{randstr:16h}" +# } +# } + + # + # Reject packets where User-Name != TLS-Client-Cert-Common-Name + # There is no reason for users to lie about their names. + # + # In general, User-Name == EAP Identity == TLS-Client-Cert-Common-Name + # +# verify_tls_client_common_name + + # + # If there is no Stripped-User-Name in the request, AND we have a client cert, + # then create a Stripped-User-Name from the TLS client certificate information. + # + # Note that this policy MUST be edited for your local system! + # We do not know which fields exist in which certificate, as + # there is no standard here. There is no way for us to have + # a default configuration which "just works" everywhere. We + # can only make recommendations. + # + # The Stripped-User-Name is updated so that it is logged in + # the various "username" fields. This logging means that you + # can associate a particular session with a particular client + # certificate. + # +# if (&EAP-Message && !&Stripped-User-Name && &TLS-Client-Cert-Serial) { +# update request { +# &Stripped-User-Name := "%{%{TLS-Client-Cert-Subject-Alt-Name-Email}:-%{%{TLS-Client-Cert-Common-Name}:-%{TLS-Client-Cert-Serial}}}" +# } +# + # + # Create a Class attribute which is a hash of a bunch + # of information which we hope exists. This + # attribute should be echoed back in + # Accounting-Request packets, which will let the + # administrator correlate authentication and + # accounting. + # +# update reply { +# Class += "%{md5:%{Calling-Station-Id}%{Called-Station-Id}%{TLS-Client-Cert-Subject-Alt-Name-Email}%{TLS-Client-Cert-Common-Name}%{TLS-Client-Cert-Serial}%{NAS-IPv6-Address}%{NAS-IP-Address}%{NAS-Identifier}%{NAS-Port}" +# } +# +# } + + # + # For EAP-TTLS and PEAP, add the cached attributes to the reply. + # The "session-state" attributes are automatically cached when + # an Access-Challenge is sent, and automatically retrieved + # when an Access-Request is received. + # + # The session-state attributes are automatically deleted after + # an Access-Reject or Access-Accept is sent. + # + # If both session-state and reply contain a User-Name attribute, remove + # the one in the reply if it is just a copy of the one in the request, so + # we don't end up with two User-Name attributes. + + if (session-state:User-Name && reply:User-Name && request:User-Name && (reply:User-Name == request:User-Name)) { + update reply { + &User-Name !* ANY + } + } + update { + &reply: += &session-state: + } + + # + # Refresh leases when we see a start or alive. Return an address to + # the IP Pool when we see a stop record. + # + # Ensure that &control:Pool-Name is set to determine which + # pool of IPs are used. +# sqlippool + + + # Create the CUI value and add the attribute to Access-Accept. + # Uncomment the line below if *returning* the CUI. +# cui + + # Create empty accounting session to make simultaneous check more robust. See the accounting queries configuration in + # raddb/mods-config/sql/main/*/queries.conf for details. + # + # The "sql_session_start" policy is defined in raddb/policy.d/accounting. See that file for more details. +# sql_session_start + + # + # If you want to have a log of authentication replies, + # un-comment the following line, and enable the + # 'detail reply_log' module. +# reply_log + + # + # After authenticating the user, do another SQL query. + # + # See "Authentication Logging Queries" in mods-available/sql + -sql + + # + # Un-comment the following if you want to modify the user's object + # in LDAP after a successful login. + # +# ldap + + # For Exec-Program and Exec-Program-Wait + exec + + # + # In order to calcualate the various keys for old style WiMAX + # (non LTE) you will need to define the WiMAX NAI, usually via + # + # update request { + # &WiMAX-MN-NAI = "%{User-Name}" + # } + # + # If you want various keys to be calculated, you will need to + # update the reply with "template" values. The module will see + # this, and replace the template values with the correct ones + # taken from the cryptographic calculations. e.g. + # + # update reply { + # &WiMAX-FA-RK-Key = 0x00 + # &WiMAX-MSK = "%{reply:EAP-MSK}" + # } + # + # You may want to delete the MS-MPPE-*-Keys from the reply, + # as some WiMAX clients behave badly when those attributes + # are included. See "raddb/modules/wimax", configuration + # entry "delete_mppe_keys" for more information. + # + # For LTE style WiMAX you need to populate the following with the + # relevant values: + # control:WiMAX-SIM-Ki + # control:WiMAX-SIM-OPc + # control:WiMAX-SIM-AMF + # control:WiMAX-SIM-SQN + # +# wimax + + # If there is a client certificate (EAP-TLS, sometimes PEAP + # and TTLS), then some attributes are filled out after the + # certificate verification has been performed. These fields + # MAY be available during the authentication, or they may be + # available only in the "post-auth" section. + # + # The first set of attributes contains information about the + # issuing certificate which is being used. The second + # contains information about the client certificate (if + # available). +# +# update reply { +# Reply-Message += "%{TLS-Cert-Serial}" +# Reply-Message += "%{TLS-Cert-Expiration}" +# Reply-Message += "%{TLS-Cert-Subject}" +# Reply-Message += "%{TLS-Cert-Issuer}" +# Reply-Message += "%{TLS-Cert-Common-Name}" +# Reply-Message += "%{TLS-Cert-Subject-Alt-Name-Email}" +# +# Reply-Message += "%{TLS-Client-Cert-Serial}" +# Reply-Message += "%{TLS-Client-Cert-Expiration}" +# Reply-Message += "%{TLS-Client-Cert-Subject}" +# Reply-Message += "%{TLS-Client-Cert-Issuer}" +# Reply-Message += "%{TLS-Client-Cert-Common-Name}" +# Reply-Message += "%{TLS-Client-Cert-Subject-Alt-Name-Email}" +# } + + # Insert class attribute (with unique value) into response, + # aids matching auth and acct records, and protects against duplicate + # Acct-Session-Id. Note: Only works if the NAS has implemented + # RFC 2865 behaviour for the class attribute, AND if the NAS + # supports long Class attributes. Many older or cheap NASes + # only support 16-octet Class attributes. +# insert_acct_class + + # MacSEC requires the use of EAP-Key-Name. However, we don't + # want to send it for all EAP sessions. Therefore, the EAP + # modules put required data into the EAP-Session-Id attribute. + # This attribute is never put into a request or reply packet. + # + # Uncomment the next few lines to copy the required data into + # the EAP-Key-Name attribute +# if (&reply:EAP-Session-Id) { +# update reply { +# EAP-Key-Name := &reply:EAP-Session-Id +# } +# } + + # Remove reply message if the response contains an EAP-Message + remove_reply_message_if_eap + + # + # Access-Reject packets are sent through the REJECT sub-section of the + # post-auth section. + # + # Add the ldap module name (or instance) if you have set + # 'edir = yes' in the ldap module configuration + # + # The "session-state" attributes are not available here. + # + Post-Auth-Type REJECT { + # log failed authentications in SQL, too. + -sql + attr_filter.access_reject + + # Insert EAP-Failure message if the request was rejected by policy instead of because of an authentication failure + eap + + # Remove reply message if the response contains an EAP-Message + remove_reply_message_if_eap + } + + # Filter access challenges. + # + Post-Auth-Type Challenge { +# remove_reply_message_if_eap +# attr_filter.access_challenge.post-auth + } + + # + # The Client-Lost section will be run for a request when + # FreeRADIUS has given up waiting for an end-users client to + # respond. This is most useful for logging EAP sessions where + # the client stopped responding (likely because the + # certificate was not acceptable.) i.e. this is not for + # RADIUS clients, but for end-user systems. + # + # This will only be triggered by new packets arriving, + # and will be run at some point in the future *after* the + # original request has been discarded. + # + # Therefore the *ONLY* attributes that are available here + # are those in the session-state list. If you want data + # to log, make sure it is copied to &session-state: + # before the client stops responding. NONE of the other + # original attributes (request, reply, etc) will be + # available. + # + # This section will only be run if `postauth_client_lost` + # is enabled in the main configuration in `radiusd.conf`. + # + # Note that there are MANY reasons why an end users system + # might not respond: + # + # * it could not get the packet due to firewall issues + # * it could not get the packet due to a lossy network + # * the users system might not like the servers cert + # * the users system might not like something else... + # + # In some cases, the client is helpful enough to send us a + # TLS Alert message, saying what it doesn't like about the + # certificate. In other cases, no such message is available. + # + # All that we can know on the FreeRADIUS side is that we sent + # an Access-Challenge, and the client never sent anything + # else. The reasons WHY this happens are buried inside of + # the logs on the client system. No amount of looking at the + # FreeRADIUS logs, or poking the FreeRADIUS configuration + # will tell you why the client gave up. The answers are in + # the logs on the client side. And no, the FreeRADIUS team + # didn't write the client, so we don't know where those logs + # are, or how to get at them. + # + # Information about the TLS state changes is in the + # &session-state:TLS-Session-Information attribute. + # + Post-Auth-Type Client-Lost { + # + # Debug ALL of the TLS state changes done during the + # EAP negotiation. + # +# %{debug_attr:&session-state:TLS-Session-Information[*]} + + # + # Debug the LAST TLS state change done during the EAP + # negotiation. For errors, this is usually a TLS + # alert from the client saying something like + # "unknown CA". + # +# %{debug_attr:&session-state:TLS-Session-Information[n]} + + # + # Debug the last module failure message. This may be + # useful, or it may refer to a server-side failure + # which did not cause the client to stop talking to the server. + # +# %{debug_attr:&session-state:Module-Failure-Message} + } + + # + # If the client sends EAP-Key-Name in the request, + # then echo the real value back in the reply. + # + if (EAP-Key-Name && &reply:EAP-Session-Id) { + update reply { + &EAP-Key-Name := &reply:EAP-Session-Id + } + } +} + +# +# When the server decides to proxy a request to a home server, +# the proxied request is first passed through the pre-proxy +# stage. This stage can re-write the request, or decide to +# cancel the proxy. +# +# Only a few modules currently have this method. +# +pre-proxy { + # Before proxing the request add an Operator-Name attribute identifying + # if the operator-name is found for this client. + # No need to uncomment this if you have already enabled this in + # the authorize section. +# operator-name + + # The client requests the CUI by sending a CUI attribute + # containing one zero byte. + # Uncomment the line below if *requesting* the CUI. +# cui + + # Uncomment the following line if you want to change attributes + # as defined in the preproxy_users file. +# files + + # Uncomment the following line if you want to filter requests + # sent to remote servers based on the rules defined in the + # 'attrs.pre-proxy' file. +# attr_filter.pre-proxy + + # If you want to have a log of packets proxied to a home + # server, un-comment the following line, and the + # 'detail pre_proxy_log' section, above. +# pre_proxy_log +} + +# +# When the server receives a reply to a request it proxied +# to a home server, the request may be massaged here, in the +# post-proxy stage. +# +post-proxy { + + # If you want to have a log of replies from a home server, + # un-comment the following line, and the 'detail post_proxy_log' + # section, above. +# post_proxy_log + + # Uncomment the following line if you want to filter replies from + # remote proxies based on the rules defined in the 'attrs' file. +# attr_filter.post-proxy + + # + # If you are proxying LEAP, you MUST configure the EAP + # module, and you MUST list it here, in the post-proxy + # stage. + # + # You MUST also use the 'nostrip' option in the 'realm' + # configuration. Otherwise, the User-Name attribute + # in the proxied request will not match the user name + # hidden inside of the EAP packet, and the end server will + # reject the EAP request. + # + eap + + # + # If the server tries to proxy a request and fails, then the + # request is processed through the modules in this section. + # + # The main use of this section is to permit robust proxying + # of accounting packets. The server can be configured to + # proxy accounting packets as part of normal processing. + # Then, if the home server goes down, accounting packets can + # be logged to a local "detail" file, for processing with + # radrelay. When the home server comes back up, radrelay + # will read the detail file, and send the packets to the + # home server. + # + # See the "mods-available/detail.example.com" file for more + # details on writing a detail file specifically for one + # destination. + # + # See the "sites-available/robust-proxy-accounting" virtual + # server for more details on reading this "detail" file. + # + # With this configuration, the server always responds to + # Accounting-Requests from the NAS, but only writes + # accounting packets to disk if the home server is down. + # +# Post-Proxy-Type Fail-Accounting { +# detail.example.com +# } +} +} \ No newline at end of file diff --git a/files/sites-available/dhcp b/files/sites-available/dhcp new file mode 100644 index 0000000..f8f8416 --- /dev/null +++ b/files/sites-available/dhcp @@ -0,0 +1,595 @@ +# -*- text -*- +###################################################################### +# +# This is a virtual server that handles DHCP. +# +# See raddb/mods-available/dhcp_sqlippool for the IP Pool configuration. +# +# See raddb/policy.d/dhcp_sqlippool for the "glue" code that allows +# the RADIUS based "sqlippool" module to be used for DHCP. +# +# See raddb/mods-config/sql/ippool/ for the schemas. +# +# See raddb/sites-available/dhcp for instructions on how to configure +# the DHCP server. +# +# $Id$ +# +###################################################################### + +# +# The DHCP functionality goes into a virtual server. +# +server dhcp { + +# Define a DHCP socket. +# +# The default port below is 6700, so you don't break your network. +# If you want it to do real DHCP, change this to 67, and good luck! +# +# You can also bind the DHCP socket to an interface. +# See below, and raddb/radiusd.conf for examples. +# +# This lets you run *one* DHCP server instance and have it listen on +# multiple interfaces, each with a separate policy. +# +# If you have multiple interfaces, it is a good idea to bind the +# listen section to an interface. You will also need one listen +# section per interface. +# +# FreeBSD does *not* support binding sockets to interfaces. Therefore, +# if you have multiple interfaces, broadcasts may go out of the wrong +# one, or even all interfaces. The solution is to use the "setfib" command. +# If you have a network "10.10.0/24" on LAN1, you will need to do: +# +# Pick any IP on the 10.10.0/24 network +# $ setfib 1 route add default 10.10.0.1 +# +# Edit /etc/rc.local, and add a line: +# setfib 1 /path/to/radiusd +# +# The kern must be built with the following options: +# options ROUTETABLES=2 +# or any value larger than 2. +# +# The other only solution is to update FreeRADIUS to use BPF sockets. +# +listen { + # This is a dhcp socket. + type = dhcp + + # IP address to listen on. Will usually be the IP of the + # interface, or 0.0.0.0 + ipaddr = 0.0.0.0 + + # source IP address for unicast packets sent by the + # DHCP server. + # + # The source IP for unicast packets is chosen from the first + # one of the following items which returns a valid IP + # address: + # + # src_ipaddr + # ipaddr + # reply:DHCP-Server-IP-Address + # reply:DHCP-DHCP-Server-Identifier + # + src_ipaddr = 127.0.0.1 + + # The port should be 67 for a production network. Don't set + # it to 67 on a production network unless you really know + # what you're doing. Even if nothing is configured below, the + # server may still NAK legitimate responses from clients. + port = 6700 + + # Interface name we are listening on. See comments above. +# interface = lo0 + + # The DHCP server defaults to allowing broadcast packets. + # Set this to "no" only when the server receives *all* packets + # from a relay agent. i.e. when *no* clients are on the same + # LAN as the DHCP server. + # + # It's set to "no" here for testing. It will usually want to + # be "yes" in production, unless you are only dealing with + # relayed packets. + broadcast = no + + # On Linux if you're running the server as non-root, you + # will need to do: + # + # setcap cap_net_admin,cap_net_bind_service=eip /path/to/radiusd + # + # This will allow the server to set ARP table entries + # for newly allocated IPs, when run as the "radius" user. + # + # The above "setcap" command adds the capability to the program, + # usually so long as it is run by the "radius" user. Which means + # (oddly enough) that it no longer works when run as root! + # + # When running the server as root in debug mode, you can use: + # + # capsh --caps="cap_setpcap,cap_setuid,cap_setgid,cap_net_admin,cap_net_bind_service+eip" --keep=1 --user=radius --addamb=cap_net_admin,cap_net_bind_service -- -c "/path/to/radiusd -X" + # + # Or, simply "sudo" or "su" to the "radius" user, and then run + # the server in debug mode. + + # De-duplicate DHCP packets. If clients don't receive + # a reply within their timeout, most will re-transmit. + # A reply to either packet will satisfy, so de-duplicating + # helps manage load on a busy server + performance { + skip_duplicate_checks = no + } +} + +# Packets received on the socket will be processed through one +# of the following sections, named after the DHCP packet type. +# See dictionary.dhcp for the packet types. + +# Return packets will be sent to, in preference order: +# DHCP-Gateway-IP-Address +# DHCP-Client-IP-Address +# DHCP-Your-IP-Address +# At least one of these attributes should be set at the end of each +# section for a response to be sent. + +# An internal attribute of DHCP-Network-Subnet is set to provide +# a basis for determining the network that a client belongs to. This +# is a hierarchical assignment based on: +# +# - DHCP-Relay-Link-Selection +# - DHCP-Subnet-Selection-Option +# - DHCP-Gateway-IP-Address +# - DHCP-Client-IP-Address +# +# Except for cases where all IP allocation is performed using a mapping from +# the device MAC address to a fixed IP address the DHCP configuration will +# involve the use of one or more pools. +# +# Each pool should be composed of a set of equally valid IP addresses for the +# devices designated as users of the pool. During IP allocation the choice of +# pool is driven by setting the Pool-Name attribute which may either be +# specified directly or chosen (usually with the help of the dhcp_network +# module) based on the initial value of DHCP-Network-Subnet. +# +# DHCP-Network-Subnet indicates the network from which the request is +# originating. In cases where the originating network alone is insufficent to +# define the required IP allocated policy, DHCP-Network-Subnet may be +# overridden to force the selection of a particular pool. +# +# IP addresses belonging to a single pool that is designated for a Layer 2 +# network containing multiple subnets (a "shared-network" or "multinet" +# configuration as defined by some other DHCP servers), will by definition be +# members of distinct subnets that require their own DHCP reply parameters. In +# this case the dhcp_subnet policy can be used to set the correct +# DHCP-Subnet-Mask, DHCP-Router-Address and DHCP-Broadcast-Address options +# based on the allocated IP. + +dhcp DHCP-Discover { + + # The DHCP Server Identifier is set here since is returned in OFFERs + update control { + &DHCP-DHCP-Server-Identifier = 192.0.2.2 + } + + # Call a policy (defined in policy.d/dhcp) to set common reply attributes + dhcp_common + + # Use a "passwd" module to set group memberships in DHCP-Group-Name + # Enable mods-available/dhcp_passwd to use this + #dhcp_group_membership + + # If clients need to be assigned to a particular network based on + # an attribute in the packet rather than the calculated + # DHCP-Network-Subnet described above, then call a policy + # (defined in policy.d/dhcp) to perform the override + #dhcp_override_network + + # Use a "files" module to lookup global and subnet options + # For multiple subnets use this in place of dhcp_common + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_network + + # Do a simple mapping of MAC to assigned IP. + # + # See below for the definition of the "mac2ip" + # module. + # + #mac2ip + + # Or, allocate IPs from the DHCP pool in SQL. You may need to + # set the pool name here if you haven't set it elsewhere. + #update control { + # &Pool-Name := "local" + #} + #dhcp_sqlippool + + # If the IP address was not allocated, do something else. + # You could call a Perl, Python, or Java script here. + #if (notfound) { + # ... + #} + + # "Shared-networks" may have multiple IP subnets co-existing in a + # single Layer 2 network. If the pool for the network contains + # addresses from more that one subnet then the setting subnet-specific + # DHCP-Subnet-Mask, DHCP-Router-Address and DHCP-Broadcast-Address + # parameters must be performed after the allocation of the IP address. + # + # Set any subnet-specific parameters using this policy. + # + # Enable mods-available/dhcp_files AND uncomment dhcp_subnet in + # policy.d/dhcp to use this. + # + #dhcp_subnet + + # Use a "files" module to lookup options based on DHCP-Group-Name + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_group_options + + # Use a "files" module to lookup host specific options + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_hosts + + # As an alternative or complement to configuration files based lookup + # for options data you can instead use an SQL database. Example + # configuration is found in dhcp_policy_sql in policy.d/dhcp which + # will need to be adapted to your requirements. + #dhcp_policy_sql + + # Set the type of packet to send in reply. + # + # The server will look at the DHCP-Message-Type attribute to + # determine which type of packet to send in reply. Common + # values would be DHCP-Offer, DHCP-Ack or DHCP-NAK. See + # dictionary.dhcp for all the possible values. + # + # DHCP-Do-Not-Respond can be used to tell the server to not + # respond. + # + # In the event that DHCP-Message-Type is not set then the + # server will fall back to determining the type of reply + # based on the rcode of this section. + # + #update reply { + # DHCP-Message-Type = DHCP-Offer + #} + # + # If DHCP-Message-Type is not set, returning "ok" or + # "updated" from this section will respond with a DHCP-Offer + # message. + # + # Other rcodes will tell the server to not return any response. + # + #ok +} + +dhcp DHCP-Request { + + # You must set the DHCP Server Identifier here since this is returned + # in ACKs and is used to determine whether a request containing a + # "server-ip" field is intended for this server + update control { + &DHCP-DHCP-Server-Identifier = 192.0.2.2 + } + + # If the request is not for this server then silently discard it + if (&request:DHCP-DHCP-Server-Identifier && \ + &request:DHCP-DHCP-Server-Identifier != &control:DHCP-DHCP-Server-Identifier) { + do_not_respond + } + + # Response packet type. See DHCP-Discover section above. + #update reply { + # &DHCP-Message-Type = DHCP-Ack + #} + + # Call a policy (defined in policy.d/dhcp) to set common reply attributes + dhcp_common + + # Use a "passwd" module to set group memberships in DHCP-Group-Name + # Enable mods-available/dhcp_passwd to use this + #dhcp_group_membership + + # Optionally override the network address based on client attributes + # See Discover section + #dhcp_override_network + + # Use a "files" module to lookup global and subnet options + # For multiple subnets use this in place of dhcp_common + # Enable mods-available/dhcp_files AND uncomment dhcp_subnet in + # policy.d/dhcp to use this + # Options are set in mods-config/files/dhcp + #dhcp_network + + # Do a simple mapping of MAC to assigned IP. + # + # See below for the definition of the "mac2ip" + # module. + # + #mac2ip + + # Or, allocate IPs from the DHCP pool in SQL. You may need to + # set the pool name here if you haven't set it elsewhere. +# update control { +# &Pool-Name := "local" +# } +# dhcp_sqlippool_request + + # If the IP was not allocated, do something else. + # You could call a Perl, Python, or Java script here. + #if (notfound) { + # ... + #} + + # "Shared-networks" may have multiple IP subnets co-existing in a + # single Layer 2 network. If the pool for the network contains + # addresses from more that one subnet then the setting subnet-specific + # DHCP-Subnet-Mask, DHCP-Router-Address and DHCP-Broadcast-Address + # parameters must be performed after the allocation of the IP address. + # + # Set any subnet-specific parameters using this policy. + # + #dhcp_subnet + + # Use a "files" module to lookup options based on DHCP-Group-Name + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_group_options + + # Use a "files" module to lookup host specific options + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_hosts + + # As an alternative or complement to configuration files based lookup + # for options data you can instead use an SQL database. Example + # configuration is found in dhcp_policy_sql in policy.d/dhcp which + # will need to be adapted to your requirements. + #dhcp_policy_sql + + # If DHCP-Message-Type is not set, returning "ok" or + # "updated" from this section will respond with a DHCP-Ack + # packet. + # + # "handled" will not return a packet, all other rcodes will + # send back a DHCP-NAK. + # + #ok +} + +# +# Other DHCP packet types +# +# There should be a separate section for each DHCP message type. +# By default this configuration will ignore them all. Any packet type +# not defined here will be responded to with a DHCP-NAK. + +dhcp DHCP-Decline { + + # Use a "passwd" module to set group memberships in DHCP-Group-Name + # Enable mods-available/dhcp_passwd to use this + #dhcp_group_membership + + # Optionally override the network address based on client attributes + # See Discover section + #dhcp_override_network + + # Use a "files" module to lookup global and subnet options + # For multiple networks use this in place of dhcp_common + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_network + + # Use a policy that set options from data stored in an SQL database + #dhcp_policy_sql + + # If using IPs from a DHCP pool in SQL then you may need to set the + # pool name here if you haven't set it elsewhere and release the IP. +# update control { +# &Pool-Name := "local" +# } +# dhcp_sqlippool_decline + + update reply { + &DHCP-Message-Type = DHCP-Do-Not-Respond + } + reject +} + +# +# A dummy config for Inform packets - this should match the +# options set in the Request section above, except Inform replies +# must not set Your-IP-Address or IP-Address-Lease-Time +# +dhcp DHCP-Inform { + # Call a policy (defined in policy.d/dhcp) to set common reply attributes + dhcp_common + + # Use a "passwd" module to set group memberships in DHCP-Group-Name + # Enable mods-available/dhcp_passwd to use this + #dhcp_group_membership + + # Optionally override the network address based on client attributes + # See Discover section + #dhcp_override_network + + # Use a "files" module to lookup global and network options + # For multiple networks use this in place of dhcp_common + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_network + + # Use a policy with calls a "files" module of the same name to lookup + # subnet options + # Enable mods-available/dhcp_files AND uncomment dhcp_subnet in + # policy.d/dhcp to use this + # Options are set in mods-config/files/dhcp + #dhcp_subnet + + # Use a "files" module to lookup options based on DHCP-Group-Name + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_group_options + + # Use a "files" module to lookup host specific options + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_hosts + + # Use a policy that set options from data stored in an SQL database + #dhcp_policy_sql + + ok +} + +# +# For Windows 7 boxes +# +#dhcp DHCP-Inform { +# update reply { +# Packet-Dst-Port = 67 +# DHCP-Message-Type = DHCP-ACK +# DHCP-DHCP-Server-Identifier = "%{Packet-Dst-IP-Address}" +# DHCP-Site-specific-28 = 0x0a00 +# } +# ok +#} + +dhcp DHCP-Release { + + # Use a "passwd" module to set group memberships in DHCP-Group-Name + # Enable mods-available/dhcp_passwd to use this + #dhcp_group_membership + + # Optionally override the network address based on client attributes + # See Discover section + #dhcp_override_network + + # Use a "files" module to lookup global and subnet options + # For multiple subnets use this in place of dhcp_common + # Enable mods-available/dhcp_files to use this + # Options are set in mods-config/files/dhcp + #dhcp_network + + # If using IPs from a DHCP pool in SQL then you may need to set the + # pool name here if you haven't set it elsewhere and release the IP. +# update control { +# &Pool-Name := "local" +# } +# dhcp_sqlippool_release + + update reply { + &DHCP-Message-Type = DHCP-Do-Not-Respond + } + reject +} + + +dhcp DHCP-Lease-Query { + # The thing being queried for is implicit + # in the packets. + + # has MAC, asking for IP, etc. + if (&DHCP-Client-Hardware-Address) { + # look up MAC in database + } + + # has IP, asking for MAC, etc. + elsif (&DHCP-Your-IP-Address) { + # look up IP in database + } + + # has host name, asking for IP, MAC, etc. + elsif (&DHCP-Client-Identifier) { + # look up identifier in database + } + else { + update reply { + &DHCP-Message-Type = DHCP-Lease-Unknown + } + + ok + + # stop processing + return + } + + # + # We presume that the database lookup returns "notfound" + # if it can't find anything. + # + if (notfound) { + update reply { + &DHCP-Message-Type = DHCP-Lease-Unknown + } + ok + return + } + + # + # Add more logic here. Is the lease inactive? + # If so, respond with DHCP-Lease-Unassigned. + # + # Otherwise, respond with DHCP-Lease-Active + # + + # + # Also be sure to return ALL information about + # the lease. + # + + # + # The reply types are: + # + # DHCP-Lease-Unknown + # DHCP-Lease-Active + # DHCP-Lease-Unassigned + # + update reply { + &DHCP-Message-Type = DHCP-Lease-Unassigned + } + +} + +} + +###################################################################### +# +# This next section is a sample configuration for the "passwd" +# module, that reads flat-text files. It should go into +# radiusd.conf, in the "modules" section. +# +# The file is in the format , +# +# 00:01:02:03:04:05,192.0.2.100 +# 01:01:02:03:04:05,192.0.2.101 +# 02:01:02:03:04:05,192.0.2.102 +# +# This lets you perform simple static IP assignment. +# +# There is a preconfigured "mac2ip" module setup in +# mods-available/mac2ip. To use it do: +# +# # cd raddb/ +# # ln -s ../mods-available/mac2ip mods-enabled/mac2ip +# # mkdir mods-config/passwd +# +# Then create the file mods-config/passwd/mac2ip with the above +# format. +# +###################################################################### + + +# This is an example only - see mods-available/mac2ip instead; do +# not uncomment these lines here. +# +#passwd mac2ip { +# filename = ${confdir}/mac2ip +# format = "*DHCP-Client-Hardware-Address:=DHCP-Your-IP-Address" +# delimiter = "," +#} \ No newline at end of file diff --git a/files/sites-available/inner-tunnel b/files/sites-available/inner-tunnel new file mode 100644 index 0000000..918cd35 --- /dev/null +++ b/files/sites-available/inner-tunnel @@ -0,0 +1,126 @@ +###################################################################### +# +# This is a virtual server that handles *only* inner tunnel +# requests for EAP-TTLS and PEAP types. +# +###################################################################### + +server inner-tunnel { + + listen { + ipaddr = 127.0.0.1 + port = 18120 + type = auth + } + + authorize { + filter_username + # filter_inner_identity + chap + mschap + # unix + # IPASS + suffix + # ntdomain + + update control { + &Proxy-To-Realm := LOCAL + } + + eap { + ok = return + } + + files + -sql + # smbpasswd + -ldap + # daily + expiration + logintime + pap + } + + authenticate { + Auth-Type PAP { + pap + } + + Auth-Type CHAP { + chap + } + + Auth-Type MS-CHAP { + mschap + } + + mschap + # pam + + # Auth-Type LDAP { + # ldap + # } + + eap + } + + session { + radutmp + # sql + } + + # Post-Authentication + post-auth { + # cui-inner + + # update outer.session-state { + # User-Name := &User-Name + # } + + # reply_log + -sql + # ldap + # moonshot_host_tid + # moonshot_realm_tid + # moonshot_coi_tid + + if (0) { + update reply { + User-Name !* ANY + Message-Authenticator !* ANY + EAP-Message !* ANY + Proxy-State !* ANY + MS-MPPE-Encryption-Types !* ANY + MS-MPPE-Encryption-Policy !* ANY + MS-MPPE-Send-Key !* ANY + MS-MPPE-Recv-Key !* ANY + } + + update { + &outer.session-state: += &reply: + } + } + + Post-Auth-Type REJECT { + -sql + attr_filter.access_reject + + update outer.session-state { + &Module-Failure-Message := &request:Module-Failure-Message + } + } + } + + pre-proxy { + # files + # attr_filter.pre-proxy + # pre_proxy_log + } + + post-proxy { + # post_proxy_log + # attr_filter.post-proxy + eap + } + +} # inner-tunnel server block \ No newline at end of file diff --git a/files/sites-available/status b/files/sites-available/status new file mode 100644 index 0000000..74c322d --- /dev/null +++ b/files/sites-available/status @@ -0,0 +1,126 @@ +# -*- text -*- +###################################################################### +# +# A virtual server to handle ONLY Status-Server packets. +# +# Server statistics can be queried with a properly formatted +# Status-Server request. See dictionary.freeradius for comments. +# +# If radiusd.conf has "status_server = yes", then any client +# will be able to send a Status-Server packet to any port +# (listen section type "auth", "acct", or "status"), and the +# server will respond. +# +# If radiusd.conf has "status_server = no", then the server will +# ignore Status-Server packets to "auth" and "acct" ports. It +# will respond only if the Status-Server packet is sent to a +# "status" port. +# +# The server statistics are available ONLY on socket of type +# "status". Queries for statistics sent to any other port +# are ignored. +# +# Similarly, a socket of type "status" will not process +# authentication or accounting packets. This is for security. +# +# $Id: e7d4346310b837d56bffe4c991b4e5680742ebc0 $ +# +###################################################################### + +server status { + listen { + # ONLY Status-Server is allowed to this port. + # ALL other packets are ignored. + type = status + + ipaddr = $ENV{FREERADIUS_SITES_STATUS_LISTEN} + port = $ENV{FREERADIUS_SITES_STATUS_PORT} + } + + # + # We recommend that you list ONLY management clients here. + # i.e. NOT your NASes or Access Points, and for an ISP, + # DEFINITELY not any RADIUS servers that are proxying packets + # to you. + # + # If you do NOT list a client here, then any client that is + # globally defined (i.e. all of them) will be able to query + # these statistics. + # + # Do you really want your partners seeing the internal details + # of what your RADIUS server is doing? + # + client admin { + ipaddr = 127.0.0.1 + secret = $ENV{FREERADIUS_SITES_STATUS_SECRET} + } + + # Simple authorize section. The "Autz-Type Status-Server" + # section will work here, too. See "raddb/sites-available/default". + authorize { + ok + + # respond to the Status-Server request. + Autz-Type Status-Server { + ok + } + } +} + +# Statistics can be queried via a number of methods: +# +# All packets received/sent by the server (1 = auth, 2 = acct) +# FreeRADIUS-Statistics-Type = 3 +# +# All packets proxied by the server (4 = proxy-auth, 8 = proxy-acct) +# FreeRADIUS-Statistics-Type = 12 +# +# All packets sent && received: +# FreeRADIUS-Statistics-Type = 15 +# +# Internal server statistics: +# FreeRADIUS-Statistics-Type = 16 +# +# All packets for a particular client (globally defined) +# FreeRADIUS-Statistics-Type = 35 +# FreeRADIUS-Stats-Client-IP-Address = 192.0.2.1 +# +# All packets for a client attached to a "listen" ip/port +# FreeRADIUS-Statistics-Type = 35 +# FreeRADIUS-Stats-Client-IP-Address = 192.0.2.1 +# FreeRADIUS-Stats-Server-IP-Address = 127.0.0.1 +# FreeRADIUS-Stats-Server-Port = 1812 +# +# All packets for a "listen" IP/port +# FreeRADIUS-Statistics-Type = 67 +# FreeRADIUS-Stats-Server-IP-Address = 127.0.0.1 +# FreeRADIUS-Stats-Server-Port = 1812 +# +# All packets for a home server IP / port +# FreeRADIUS-Statistics-Type = 131 +# FreeRADIUS-Stats-Server-IP-Address = 192.0.2.2 +# FreeRADIUS-Stats-Server-Port = 1812 + +# +# You can also get exponentially weighted moving averages of +# response times (in usec) of home servers. Just set the config +# item "historic_average_window" in a home_server section. +# +# By default it is zero (don't calculate it). Useful values +# are between 100, and 10,000. The server will calculate and +# remember the moving average for this window, and for 10 times +# that window. +# + +# +# Some of this could have been simplified. e.g. the proxy-auth and +# proxy-acct bits aren't completely necessary. But using them permits +# the server to be queried for ALL inbound && outbound packets at once. +# This gives a good snapshot of what the server is doing. +# +# Due to internal limitations, the statistics might not be exactly up +# to date. Do not expect all of the numbers to add up perfectly. +# The Status-Server packets are also counted in the total requests && +# responses. The responses are counted only AFTER the response has +# been sent. +# diff --git a/files/sites-available/tls b/files/sites-available/tls new file mode 100644 index 0000000..28eb615 --- /dev/null +++ b/files/sites-available/tls @@ -0,0 +1,603 @@ +###################################################################### +# +# RADIUS over TLS (radsec) +# +# When a new client connects, the various TLS parameters for the +# connection are available as dynamic expansions, e.g. +# +# %{listen:TLS-Client-Cert-Common-Name} +# +# Along with other TLS-Client-Cert-... attributes. +# These expansions will only exist if the relevant fields +# are in the client certificate. Read the debug output to see +# which fields are available. Look for output like the following: +# +# (0) TLS - Creating attributes from certificate OIDs +# (0) TLS-Client-Cert-Subject-Alt-Name-Dns := "one.example.org" +# (0) TLS-Client-Cert-Subject-Alt-Name-Dns := "two.example.org" +# ... +# +# It is also possible to distinguish between connections which have +# TLS enables, and ones which do not. The expansion: +# +# %{listen:tls} +# +# Will return "yes" if the connection has TLS enabled. It will +# return "no" if TLS is not enabled for a particular listen section. +# +# A number of TLS-Client-Cert-.. attributes holds X509v3 extensions +# data, attributes named the way OpenSSL names them. It is possible +# to extract data for an extension not known to OpenSSL by defining +# a custom string attribute which contains extension OID in it's +# name after 'TLS-Client-Cert-' prefix. E.g.: +# +# ATTRIBUTE TLS-Client-Cert-1.3.6.1.4.1.311.21.7 3002 string +# +# which will yield something simmilar to: +# +# (0) eap_tls: TLS - Creating attributes from certificate OIDs +# (0) eap_tls: TLS-Client-Cert-1.3.6.1.4.1.311.21.7 += "0x302e06" +# ... +# +###################################################################### + +listen { + + # ipaddr = $ENV{FREERADIUS_SITES_TLS_LISTEN} + ipaddr = * + port = $ENV{FREERADIUS_SITES_TLS_PORT} + + # + # TCP and TLS sockets can accept Access-Request and Accounting-Request on the same socket. + # + # auth = only Access-Request + # acct = only Accounting-Request + # auth+acct = both + # coa = only CoA / Disconnect requests + # + type = auth+acct + + # For now, only TCP transport is allowed. + proto = tcp + + # Send packets to the default virtual server + virtual_server = default + + clients = radsec + + # Use the haproxy "PROXY protocol". + # + # This configuration allows for many FreeRADIUS servers to be behind a haproxy server. The "PROXY protocol" allows haproxy to send the actual client IP to FreeRADIUS. + # + # This will work ONLY for RadSec (TLS). Both the haproxy AND the RadSec client MUST be listed as allowed RADIUS clients. + # + # haproxy needs to have "send-proxy" configured for this server. Health checks should be turned off, as haproxy does not support RADIUS health checks. + # + # The main use of this feature is for scalability. There is no longer any need to have a RADIUS proxy as a load balancer. + # haproxy is fast, stable, and supports dynamic reloads! + # + # The only problem is that many RADIUS clients do not support RadSec. That situation will hopefully change over time. + # +# proxy_protocol = no + + # When this is set to "yes", new TLS connections are processed through a section called + # + # Autz-Type New-TLS-Connection { + # ... + # } + # + # The request contains TLS client certificate attributes, + # and nothing else. The debug output will print which + # attributes are available on your system. + # + # If the section returns "ok" or "updated", then the + # connection is accepted. Otherwise the connection is + # terminated. + # +# check_client_connections = yes + + # + # Connection limiting for sockets with "proto = tcp". + # + limit { + # Limit the number of simultaneous TCP connections to the socket + # + # The default is 16. + # Setting this to 0 means "no limit" + max_connections = 16 + + # The per-socket "max_requests" option does not exist. + + # The lifetime, in seconds, of a TCP connection. After this lifetime, the connection will be closed. + # + # Setting this to 0 means "forever". + lifetime = 0 + + # The idle timeout, in seconds, of a TCP connection. If no packets have been received over the connection for this time, the connection will be closed. + # + # Setting this to 0 means "no timeout". + # We STRONGLY RECOMMEND that you set an idle timeout. + # + idle_timeout = 30 + } + + # This is *exactly* the same configuration as used by the EAP-TLS + # module. It's OK for testing, but for production use it's a good + # idea to use different server certificates for EAP and for RADIUS + # transport. + # + # If you want only one TLS configuration for multiple sockets, + # then we suggest putting "tls { ...}" into radiusd.conf. + # The subsection below can then be changed into a reference: + # + # tls = ${tls} + # + # Which means "the tls sub-section is not here, but instead is in + # the top-level section called 'tls'". + # + # If you have multiple tls configurations, you can put them into + # sub-sections of a top-level "tls" section. There's no need to + # call them all "tls". You can then use: + # + # tls = ${tls.site1} + # + # to refer to the "site1" sub-section of the "tls" section. + # + tls { + private_key_password = $ENV{FREERADIUS_SITES_TLS_PRIVKEY_PASSWORD} + private_key_file = $ENV{FREERADIUS_SITES_TLS_PRIVKEY_FILE} + + # Accept an expired Certificate Revocation List + # allow_expired_crl = no + + # If Private key & Certificate are located in + # the same file, then private_key_file & + # certificate_file must contain the same file + # name. + # + # If ca_file (below) is not used, then the + # certificate_file below MUST include not + # only the server certificate, but ALSO all + # of the CA certificates used to sign the + # server certificate. + certificate_file = $ENV{FREERADIUS_SITES_TLS_CERTIFICATE_FILE} + + + # Trusted Root CA list + # + # ALL of the CA's in this list will be trusted to issue client certificates for authentication. + # + # In general, you should use self-signed certificates for 802.1x (EAP) authentication. + # In that case, this CA file should contain *one* CA certificate. + # + # This parameter is used only for EAP-TLS, when you issue client certificates. If you do not use client certificates, and you do not want + # to permit EAP-TLS authentication, then delete this configuration item. + ca_file = $ENV{FREERADIUS_SITES_TLS_CA_FILE} + + # For DH cipher suites to work, you have to run OpenSSL to create the DH file first: + # + # openssl dhparam -out certs/dh 1024 + # + # dh_file = ${certdir}/dh + + # + # If your system doesn't have /dev/urandom, + # you will need to create this file, and + # periodically change its contents. + # + # For security reasons, FreeRADIUS doesn't + # write to files in its configuration + # directory. + # + # random_file = /dev/urandom + + # + # The default fragment size is 1K. + # However, it's possible to send much more data than + # that over a TCP connection. The upper limit is 64K. + # Setting the fragment size to more than 1K means that + # there are fewer round trips when setting up a TLS + # connection. But only if the certificates are large. + # + fragment_size = 8192 + + # include_length is a flag which is + # by default set to yes If set to + # yes, Total Length of the message is + # included in EVERY packet we send. + # If set to no, Total Length of the + # message is included ONLY in the + # First packet of a fragment series. + # + # include_length = yes + + # Check the Certificate Revocation List + # + # 1) Copy CA certificates and CRLs to same directory. + # 2) Execute 'c_rehash '. + # 'c_rehash' is OpenSSL's command. + # 3) uncomment the line below. + # 5) Restart radiusd + # check_crl = yes + ca_path = ${cadir} + + # OpenSSL does not reload contents of ca_path dir over time. + # That means that if check_crl is enabled and CRLs are loaded + # from ca_path dir, at some point CRLs will expire and + # RADIUSd will stop authenticating NASes. + # If ca_path_reload_interval is non-zero, it will force OpenSSL + # to reload all data from ca_path periodically + # + # Flush ca_path each hour + ca_path_reload_interval = 3600 + + # + # If check_cert_issuer is set, the value will + # be checked against the DN of the issuer in + # the client certificate. If the values do not + # match, the certificate verification will fail, + # rejecting the user. + # + # This check can be done more generally by checking + # the value of the TLS-Client-Cert-Issuer attribute. + # This check can be done via any mechanism you choose. + # + # check_cert_issuer = "/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd" + + # + # If check_cert_cn is set, the value will + # be xlat'ed and checked against the CN + # in the client certificate. If the values + # do not match, the certificate verification + # will fail rejecting the user. + # + # This check is done only if the previous + # "check_cert_issuer" is not set, or if + # the check succeeds. + # + # In 2.1.10 and later, this check can be done + # more generally by checking the value of the + # TLS-Client-Cert-Common-Name attribute. This check + # can be done via any mechanism you choose. + # + # check_cert_cn = %{User-Name} + # + # Set this option to specify the allowed + # TLS cipher suites. The format is listed + # in "man 1 ciphers". + cipher_list = $ENV{FREERADIUS_SITES_TLS_CIPHER} + + # If enabled, OpenSSL will use server cipher list + # (possibly defined by cipher_list option above) + # for choosing right cipher suite rather than + # using client-specified list which is OpenSSl default + # behavior. Having it set to yes is a current best practice + # for TLS + cipher_server_preference = no + + # + # Older TLS versions are deprecated. But for RadSec, + # we CAN allow TLS 1.3. + # + tls_min_version = "1.2" + tls_max_version = "1.3" + + # + # Session resumption / fast reauthentication cache. + # + # The cache contains the following information: + # + # session Id - unique identifier, managed by SSL + # User-Name - from the Access-Accept + # Stripped-User-Name - from the Access-Request + # Cached-Session-Policy - from the Access-Accept + # + # The "Cached-Session-Policy" is the name of a + # policy which should be applied to the cached + # session. This policy can be used to assign + # VLANs, IP addresses, etc. It serves as a useful + # way to re-apply the policy from the original + # Access-Accept to the subsequent Access-Accept + # for the cached session. + # + # On session resumption, these attributes are + # copied from the cache, and placed into the + # reply list. + # + # You probably also want "use_tunneled_reply = yes" when using fast session resumption. + # + cache { + # + # Enable it. The default is "no". + # Deleting the entire "cache" subsection + # Also disables caching. + # + # + # As of version 3.0.14, the session cache requires the use + # of the "name" and "persist_dir" configuration items, below. + # + # The internal OpenSSL session cache has been permanently + # disabled. + # + # You can disallow resumption for a + # particular user by adding the following + # attribute to the control item list: + # + # Allow-Session-Resumption = No + # + # If "enable = no" below, you CANNOT + # enable resumption for just one user + # by setting the above attribute to "yes". + # + enable = no + + # + # Lifetime of the cached entries, in hours. + # The sessions will be deleted after this + # time. + # + lifetime = 24 # hours + + # + # Internal "name" of the session cache. + # Used to distinguish which TLS context + # sessions belong to. + # + # The server will generate a random value + # if unset. This will change across server + # restart so you MUST set the "name" if you + # want to persist sessions (see below). + # + # If you use IPv6, change the "ipaddr" below + # to "ipv6addr" + # + #name = "TLS ${..ipaddr} ${..port} ${..proto}" + + # + # Simple directory-based storage of sessions. + # Two files per session will be written, the SSL + # state and the cached VPs. This will persist session + # across server restarts. + # + # The server will need write perms, and the directory + # should be secured from anyone else. You might want + # a script to remove old files from here periodically: + # + # find ${logdir}/tlscache -mtime +2 -exec rm -f {} \; + # + # This feature REQUIRES "name" option be set above. + # + #persist_dir = "${logdir}/tlscache" + } + + # + # Require a client certificate. + # + require_client_cert = yes + + # + # As of version 2.1.10, client certificates can be + # validated via an external command. This allows + # dynamic CRLs or OCSP to be used. + # + # This configuration is commented out in the + # default configuration. Uncomment it, and configure + # the correct paths below to enable it. + # + verify { + # A temporary directory where the client + # certificates are stored. This directory + # MUST be owned by the UID of the server, + # and MUST not be accessible by any other + # users. When the server starts, it will do + # "chmod go-rwx" on the directory, for + # security reasons. The directory MUST + # exist when the server starts. + # + # You should also delete all of the files + # in the directory when the server starts. + # tmpdir = /tmp/radiusd + # tmpdir = /startechnica/freeradius/tmp + + # The command used to verify the client cert. + # We recommend using the OpenSSL command-line + # tool. + # + # The ${..ca_path} text is a reference to + # the ca_path variable defined above. + # + # The %{TLS-Client-Cert-Filename} is the name + # of the temporary file containing the cert + # in PEM format. This file is automatically + # deleted by the server when the command + # returns. + # client = "/path/to/openssl verify -CApath ${..ca_path} %{TLS-Client-Cert-Filename}" + } + } +} + +clients radsec { + client 127.0.0.1 { + ipaddr = 127.0.0.1 + + # Ensure that this client is TLS *only*. + proto = tls + + # TCP clients can have any shared secret. + # TLS clients MUST have the shared secret set to "radsec". Or, for "proto = tls", you can omit the secret, and it will + # automatically be set to "radsec". + # secret = radsec + secret = $ENV{FREERADIUS_CLIENTS_SECRET} + + # You can also use a "limit" section here. + # See raddb/clients.conf for examples. + # + # Note that BOTH limits are applied. You should therefore set the "listen" limits higher than the ones for each individual + # client. + } +} + +# When a request is proxied to a TLS-enabled home server, the TLS parameters are available via the expansion: +# +# %{proxy_listen: ... } +# +# The contents of the expansion are the same as described above with the %{listen: ... } expansion, and have similar meanings. "client" in this case is the proxy (this system) +# and "server" is the remote system (home server). +# +# Note that the %{proxy_listen: ... } parameters are available only AFTER the connection has been made to the home server. +home_server tls { + ipaddr = 127.0.0.1 + port = $ENV{FREERADIUS_SITES_TLS_PORT} + + # type can be the same types as for the "listen" section/ + # e.g. auth, acct, auth+acct, coa + type = auth + secret = radsec + proto = tcp + status_check = none + + tls { + # + # Similarly to HTTP, the client can use Server Name + # Indication to inform the RadSec server of which + # domain it is requesting. This selection allows + # multiple sites to exist at the same IP address. + # + # For example, and identity provider could host + # multiple sites, but present itself with one public + # IP address. + # + # SNI also permits the use of a load balancer such as + # haproxy. That load balancer can terminate the TLS + # connection, and then use SNI to route the + # underlying RADIUS TCP traffic to a particular host. + # + # Note that "hostname" here is only for SNI, and is NOT + # the hostname or IP address we connect to. For that, + # see "ipaddr", above. + # + # hostname = "example.com" + + private_key_password = $ENV{FREERADIUS_SITES_TLS_PRIVKEY_PASSWORD} + # private_key_file = ${certdir}/client.pem + private_key_file = $ENV{FREERADIUS_SITES_TLS_PRIVKEY_FILE} + + # If Private key & Certificate are located in + # the same file, then private_key_file & + # certificate_file must contain the same file + # name. + # + # If ca_file (below) is not used, then the + # certificate_file below MUST include not + # only the server certificate, but ALSO all + # of the CA certificates used to sign the + # server certificate. + # certificate_file = ${certdir}/client.pem + certificate_file = $ENV{FREERADIUS_SITES_TLS_CERTIFICATE_FILE} + + # Trusted Root CA list + # + # ALL of the CA's in this list will be trusted to issue client certificates for authentication. + # + # In general, you should use self-signed certificates for 802.1x (EAP) authentication. + # In that case, this CA file should contain *one* CA certificate. + # + # This parameter is used only for EAP-TLS, + # when you issue client certificates. If you do + # not use client certificates, and you do not want + # to permit EAP-TLS authentication, then delete + # this configuration item. + ca_file = $ENV{FREERADIUS_SITES_TLS_CA_FILE} + + # + # For TLS-PSK, the key should be specified dynamically, instead of using a hard-coded psk_identity and psk_hexphrase. + # + # The input to the dynamic expansion will be the PSK + # identity supplied by the client, in the + # TLS-PSK-Identity attribute. The output of the + # expansion should be a hex string, of no more than + # 512 characters. The string should not be prefixed + # with "0x". e.g. "abcdef" is OK. "0xabcdef" is not. + # + # psk_query = "%{psksql:select hex(key) from psk_keys where keyid = '%{TLS-PSK-Identity}'}" + + # For DH cipher suites to work, you have to run OpenSSL to create the DH file first: + # + # openssl dhparam -out certs/dh 1024 + # + dh_file = ${certdir}/dh + random_file = /dev/urandom + + # + # The default fragment size is 1K. + # However, TLS can send 64K of data at once. + # It can be useful to set it higher. + # + fragment_size = 8192 + + # include_length is a flag which is + # by default set to yes If set to + # yes, Total Length of the message is + # included in EVERY packet we send. + # If set to no, Total Length of the + # message is included ONLY in the + # First packet of a fragment series. + # + # include_length = yes + + # Check the Certificate Revocation List + # + # 1) Copy CA certificates and CRLs to same directory. + # 2) Execute 'c_rehash '. + # 'c_rehash' is OpenSSL's command. + # 3) uncomment the line below. + # 5) Restart radiusd + # check_crl = yes + ca_path = ${cadir} + + # + # If check_cert_issuer is set, the value will + # be checked against the DN of the issuer in + # the client certificate. If the values do not + # match, the certificate verification will fail, + # rejecting the user. + # + # In 2.1.10 and later, this check can be done + # more generally by checking the value of the + # TLS-Client-Cert-Issuer attribute. This check + # can be done via any mechanism you choose. + # + # check_cert_issuer = "/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd" + + # + # If check_cert_cn is set, the value will + # be xlat'ed and checked against the CN + # in the client certificate. If the values + # do not match, the certificate verification + # will fail rejecting the user. + # + # This check is done only if the previous + # "check_cert_issuer" is not set, or if + # the check succeeds. + # + # In 2.1.10 and later, this check can be done + # more generally by checking the value of the + # TLS-Client-Cert-Common-Name attribute. This check + # can be done via any mechanism you choose. + # + # check_cert_cn = %{User-Name} + # + # Set this option to specify the allowed TLS cipher suites. The format is listed in "man 1 ciphers". + cipher_list = $ENV{FREERADIUS_SITES_TLS_CIPHER} + } + +} + +home_server_pool tls { + type = fail-over + home_server = tls +} + +realm tls { + auth_pool = tls +} \ No newline at end of file diff --git a/index.yaml b/index.yaml new file mode 100644 index 0000000..3e351c1 --- /dev/null +++ b/index.yaml @@ -0,0 +1,115 @@ +apiVersion: v1 +entries: + freeradius: + - annotations: + category: AccessManagement + apiVersion: v2 + appVersion: 3.2.7 + created: "2025-06-16T16:16:37.456715181+02:00" + dependencies: + - name: st-common + repository: https://startechnica.github.io/apps + version: 0.1.12 + - condition: mariadb.enabled + name: mariadb + repository: oci://registry-1.docker.io/bitnamicharts + version: 20.x.x + description: FreeRADIUS is a modular, high performance free RADIUS suite developed + and distributed under the GNU General Public License, version 2, and is free + for download and use. + digest: da3ba6c773298d8e6ff0df4cb8eb2d9effb81e92d4991a74908a136c70457920 + home: https://github.com/startechnica/apps/tree/main/charts/freeradius + icon: https://freeradius.org/img/wordmark.svg + keywords: + - freeradius + - radius + - mysql + - postgresql + - ldap + kubeVersion: '>=1.24.0-0' + maintainers: + - email: firmansyah@nainggolan.id + name: firmansyahn + url: https://firmansyah.nainggolan.id + name: freeradius + sources: + - https://freeradius.org/ + - https://github.com/FreeRADIUS/freeradius-server + type: application + urls: + - freeradius-1.0.3.tgz + version: 1.0.3 + mariadb: + - annotations: + category: Database + images: | + - name: mariadb + image: docker.io/bitnami/mariadb:11.4.7-debian-12-r1 + - name: mysqld-exporter + image: docker.io/bitnami/mysqld-exporter:0.17.2-debian-12-r11 + - name: os-shell + image: docker.io/bitnami/os-shell:12-debian-12-r46 + licenses: Apache-2.0 + tanzuCategory: service + apiVersion: v2 + appVersion: 11.4.7 + created: "2025-06-16T16:16:37.459591908+02:00" + dependencies: + - name: common + repository: oci://registry-1.docker.io/bitnamicharts + tags: + - bitnami-common + version: 2.x.x + description: MariaDB is an open source, community-developed SQL database server + that is widely in use around the world due to its enterprise features, flexibility, + and collaboration with leading tech firms. + digest: 1e5034974b28d6ab585efdaf9a345ea4e4d3024417b680b83f656a4c0b1e2a84 + home: https://bitnami.com + icon: https://dyltqmyl993wv.cloudfront.net/assets/stacks/mariadb/img/mariadb-stack-220x234.png + keywords: + - mariadb + - mysql + - database + - sql + - prometheus + maintainers: + - name: Broadcom, Inc. All Rights Reserved. + url: https://github.com/bitnami/charts + name: mariadb + sources: + - https://github.com/bitnami/charts/tree/main/bitnami/mariadb + urls: + - charts/mariadb-20.5.7.tgz + version: 20.5.7 + st-common: + - annotations: + artifacthub.io/changes: | + - kind: added + description: Add dotenv and envvars names helper + category: Infrastructure + apiVersion: v2 + appVersion: 0.1.12 + created: "2025-06-16T16:16:37.460145288+02:00" + description: A Library Helm Chart for grouping common logic between Startechnica + charts. This chart is not deployable by itself. + digest: 4c1c7304cf4dbb900b6fd847cf1d38e6f8d1db46dbf080b4d52c884b84a36747 + home: https://github.com/startechnica/apps/tree/main/charts/common + icon: https://startechnica.github.io/apps/images/star.png + keywords: + - common + - helper + - template + - function + kubeVersion: '>=1.20.0-0' + maintainers: + - email: firmansyah@nainggolan.id + name: firmansyahn + url: https://firmansyah.nainggolan.id + name: st-common + sources: + - https://startechnica.github.io/apps + type: library + urls: + - charts/st-common-0.1.12.tgz + version: 0.1.12 +generated: "2025-06-16T16:16:37.449242718+02:00" diff --git a/packages/freeradius-1.0.3.tgz b/packages/freeradius-1.0.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ab7f158b7c55e59235869d384300e100b82297da GIT binary patch literal 158980 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 Gf)D_*atE9M literal 0 HcmV?d00001 diff --git a/templates/Certificate.yaml b/templates/Certificate.yaml new file mode 100644 index 0000000..9a65f83 --- /dev/null +++ b/templates/Certificate.yaml @@ -0,0 +1,54 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if and (include "freeradius.createTlsSecret" .) .Values.tls.autoGenerator.certmanager.enabled }} +{{- if not (eq (include "st-common.capabilities.certManager.apiVersion" .) "false") }} +{{- $releaseNamespace := include "st-common.names.namespace" . }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $fullname := include "st-common.names.fullname" . }} +{{- $serviceName := include "st-common.names.fullname" . }} +{{- $altNames := list (printf "%s.%s.svc.%s" $serviceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc" $serviceName $releaseNamespace) (printf "%s.%s" $serviceName $releaseNamespace) $fullname }} +{{/* +{{- $altNames := list (printf "*.%s.%s.svc.%s" $serviceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc" $serviceName $releaseNamespace) (printf "%s.%s" $serviceName $releaseNamespace) $fullname }} +*/}} +apiVersion: {{ include "st-common.capabilities.certManager.apiVersion" . }} +kind: Certificate +metadata: + name: {{ include "st-common.names.fullname" . }}-tls + namespace: {{ include "st-common.names.namespace" . | quote }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} +spec: + secretName: {{ include "freeradius.tlsSecretName" . }} + issuerRef: + group: cert-manager.io + kind: {{ .Values.tls.autoGenerator.certmanager.issuerKind }} + name: {{ .Values.tls.autoGenerator.certmanager.issuerName }} + #name: letsencrypt-prd + privateKey: + algorithm: ECDSA + rotationPolicy: Always + size: 256 + subject: + organizations: + - {{ .Release.Name | quote }} + organizationalUnits: + - {{ include "st-common.names.fullname" . }} + dnsNames: + - {{ .Values.ingress.hostname | quote }} + {{- range .Values.ingress.extraHosts }} + - {{ .name | quote }} + {{- end }} + {{- with $altNames }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} +--- \ No newline at end of file diff --git a/templates/ConfigMap/clients.yaml b/templates/ConfigMap/clients.yaml new file mode 100644 index 0000000..afbe928 --- /dev/null +++ b/templates/ConfigMap/clients.yaml @@ -0,0 +1,23 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if not .Values.clients.existingConfigMapName }} +{{- $client := index .Values "clients" "localhost" }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-clients" (include "st-common.names.fullname" .) }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +data: + clients.conf: |- + client +{{- end }} \ No newline at end of file diff --git a/templates/ConfigMap/envvars.yaml b/templates/ConfigMap/envvars.yaml new file mode 100644 index 0000000..2b6b3a1 --- /dev/null +++ b/templates/ConfigMap/envvars.yaml @@ -0,0 +1,75 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "freeradius.names.envvars" . }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +data: + FREERADIUS_ENABLE_TLS: {{ ternary "true" "false" .Values.tls.enabled | quote }} + + FREERADIUS_CLIENTS_SHORTNAME: "" + FREERADIUS_CLIENTS_IPV4ADDR: "" + FREERADIUS_CLIENTS_IPV6ADDR: "" + FREERADIUS_CLIENTS_SECRET: "" + + {{- if .Values.modsEnabled.sql.enabled }} + FREERADIUS_MODS_SQL_DIALECT: {{ .Values.modsEnabled.sql.dialect }} + FREERADIUS_MODS_SQL_SERVER: {{ include "freeradius.database.host" . | quote }} + FREERADIUS_MODS_SQL_PORT: {{ include "freeradius.database.port" . }} + FREERADIUS_MODS_SQL_LOGIN: {{ include "freeradius.database.user" . | quote }} + FREERADIUS_MODS_SQL_DB: {{ include "freeradius.database.name" . | quote }} + FREERADIUS_MODS_SQL_TABLE_ACCT1: {{ .Values.modsEnabled.sql.table.acct1 }} + FREERADIUS_MODS_SQL_TABLE_ACCT2: {{ .Values.modsEnabled.sql.table.acct2 }} + FREERADIUS_MODS_SQL_TABLE_AUTHCHECK: {{ .Values.modsEnabled.sql.table.authcheck }} + FREERADIUS_MODS_SQL_TABLE_AUTHREPLY: {{ .Values.modsEnabled.sql.table.authreply }} + FREERADIUS_MODS_SQL_TABLE_CLIENT: {{ .Values.modsEnabled.sql.table.client }} + FREERADIUS_MODS_SQL_TABLE_GROUPCHECK: {{ .Values.modsEnabled.sql.table.groupcheck }} + FREERADIUS_MODS_SQL_TABLE_GROUPREPLY: {{ .Values.modsEnabled.sql.table.groupreply }} + FREERADIUS_MODS_SQL_TABLE_POSTAUTH: {{ .Values.modsEnabled.sql.table.postauth }} + FREERADIUS_MODS_SQL_TABLE_USERGROUP: {{ .Values.modsEnabled.sql.table.usergroup }} + FREERADIUS_MODS_SQL_TLS_ENABLE: {{ ternary "yes" "no" .Values.modsEnabled.sql.tls.enabled | quote }} + + FREERADIUS_MODS_SQL_READ_CLIENTS: {{ ternary "yes" "no" .Values.modsEnabled.sql.readClients | quote }} + FREERADIUS_MODS_SQL_GROUP_ATTRIBUTE: {{ .Values.modsEnabled.sql.groupAttribute | quote }} + + FREERADIUS_MODS_SQL_SQLITE_FILENAME: {{ .Values.modsEnabled.sql.sqlite.filename | quote }} + FREERADIUS_MODS_SQL_SQLITE_BUSY_TIMEOUT: {{ .Values.modsEnabled.sql.sqlite.busyTimeout | quote }} + + {{- if .Values.modsEnabled.sql.tls.enabled }} + FREERADIUS_MODS_SQL_TLS_CACERT: {{ include "freeradius.sqlTlsCACert" . | quote }} + FREERADIUS_MODS_SQL_TLS_CIPHER: {{ .Values.modsEnabled.sql.tls.ciphers | quote }} + FREERADIUS_MODS_SQL_TLS_CERTIFICATE: {{ include "freeradius.sqlTlsCert" . | quote }} + FREERADIUS_MODS_SQL_TLS_PRIVATEKEY: {{ include "freeradius.sqlTlsCertKey" . | quote }} + FREERADIUS_MODS_SQL_TLS_PRIVATEKEY_PASSWORD: {{ .Values.modsEnabled.sql.tls.privateKeyPassword | quote }} + {{- end }} + {{- end }} + + FREERADIUS_SITES_NAMESPACE: radius + + FREERADIUS_SITES_DEFAULT_AUTH_PORT: {{ .Values.containerPorts.auth | quote }} + FREERADIUS_SITES_DEFAULT_ACCT_PORT: {{ .Values.containerPorts.acct | quote }} + {{- if .Values.sitesEnabled.coa.enabled }} + FREERADIUS_SITES_COA_PORT: {{ .Values.containerPorts.coa | quote }} + {{- end }} + {{- if .Values.sitesEnabled.status.enabled }} + FREERADIUS_SITES_STATUS_LISTEN: {{ .Values.sitesEnabled.status.listen | quote }} + FREERADIUS_SITES_STATUS_PORT: {{ .Values.containerPorts.status | quote }} + {{- end }} + {{- if .Values.sitesEnabled.tls.enabled }} + FREERADIUS_SITES_TLS_PORT: {{ .Values.containerPorts.radsec | quote }} + FREERADIUS_SITES_TLS_CA_FILE: {{ include "freeradius.tlsCACert" . | quote }} + FREERADIUS_SITES_TLS_CERTIFICATE_FILE: {{ include "freeradius.tlsCert" . | quote }} + FREERADIUS_SITES_TLS_CIPHER: {{ default "DEFAULT" .Values.sitesEnabled.tls.cipher | quote }} + FREERADIUS_SITES_TLS_PRIVKEY_FILE: {{ include "freeradius.tlsCertKey" . | quote }} + {{- end }} diff --git a/templates/ConfigMap/mods-enabled.yaml b/templates/ConfigMap/mods-enabled.yaml new file mode 100644 index 0000000..169bc9f --- /dev/null +++ b/templates/ConfigMap/mods-enabled.yaml @@ -0,0 +1,21 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-mods" (include "st-common.names.fullname" .) }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +data: +{{- if .Values.modsEnabled.sql.enabled }} +{{ (.Files.Glob "files/mods-available/sql").AsConfig | indent 2 }} +{{- end }} diff --git a/templates/ConfigMap/sites-enabled.yaml b/templates/ConfigMap/sites-enabled.yaml new file mode 100644 index 0000000..d751767 --- /dev/null +++ b/templates/ConfigMap/sites-enabled.yaml @@ -0,0 +1,29 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-sites" (include "st-common.names.fullname" .) }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +data: +{{ (.Files.Glob "files/sites-available/default").AsConfig | indent 2 }} +{{ (.Files.Glob "files/sites-available/inner-tunnel").AsConfig | indent 2 }} +{{- if .Values.sitesEnabled.coa.enabled }} +{{ (.Files.Glob "files/sites-available/coa").AsConfig | indent 2 }} +{{- end }} +{{- if .Values.sitesEnabled.status.enabled }} +{{ (.Files.Glob "files/sites-available/status").AsConfig | indent 2 }} +{{- end }} +{{- if .Values.sitesEnabled.tls.enabled }} +{{ (.Files.Glob "files/sites-available/tls").AsConfig | indent 2 }} +{{- end }} \ No newline at end of file diff --git a/templates/Deployment.yaml b/templates/Deployment.yaml new file mode 100644 index 0000000..d173b5c --- /dev/null +++ b/templates/Deployment.yaml @@ -0,0 +1,366 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{- $globalSecretName := printf "%s" (tpl (include "st-common.secrets.name" (dict "existingSecret" .Values.auth.existingSecret "context" $)) $) }} +apiVersion: {{ include "st-common.capabilities.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: freeradius + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + selector: + matchLabels: {{- include "st-common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: freeradius + {{- if .Values.updateStrategy }} + strategy: {{- toYaml .Values.updateStrategy | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + checksum/configmap-env: {{ include (print $.Template.BasePath "/ConfigMap/envvars.yaml") . | sha256sum }} + checksum/configmap-mods: {{ include (print $.Template.BasePath "/ConfigMap/mods-enabled.yaml") . | sha256sum }} + checksum/configmap-sites: {{ include (print $.Template.BasePath "/ConfigMap/sites-enabled.yaml") . | sha256sum }} + checksum/secret-credentials: {{ include (print $.Template.BasePath "/Secret/credentials.yaml") . | sha256sum }} + checksum/secret-sql-tls: {{ include (print $.Template.BasePath "/Secret/sql-tls.yaml") . | sha256sum }} + checksum/secret-tls: {{ include (print $.Template.BasePath "/Secret/tls.yaml") . | sha256sum }} + {{- if .Values.podAnnotations }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }} + {{- end }} + labels: {{- include "st-common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: freeradius + {{- if .Values.podLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.podLabels "context" $) | nindent 8 }} + {{- end }} + spec: + {{- if .Values.affinity }} + affinity: {{- include "st-common.tplvalues.render" (dict "value" .Values.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "st-common.affinities.pods" (dict "type" .Values.podAffinityPreset "context" $) | nindent 10 }} + podAntiAffinity: {{- include "st-common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "context" $) | nindent 10 }} + nodeAffinity: {{- include "st-common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- include "freeradius.imagePullSecrets" . | nindent 6 }} + {{- if .Values.hostAliases }} + hostAliases: {{- include "st-common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: {{- include "st-common.tplvalues.render" (dict "value" .Values.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.schedulerName }} + schedulerName: {{ .Values.schedulerName | quote }} + {{- end }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "freeradius.serviceAccountName" . }} + {{- if .Values.tolerations }} + tolerations: {{- include "st-common.tplvalues.render" (dict "value" .Values.tolerations "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "st-common.tplvalues.render" (dict "value" .Values.topologySpreadConstraints "context" .) | nindent 8 }} + {{- end }} + {{- if or (and .Values.volumePermissions.enabled .Values.persistence.enabled) .Values.initContainers }} + initContainers: + {{- if .Values.initContainers }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.initContainers "context" $) | nindent 8 }} + {{- end }} + {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} + - name: volume-permissions + image: {{ include "freeradius.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + args: + - -ec + - | + printf '%s\n' "[system] Change permission" >&2 + chown -R {{ .Values.containerSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ .Values.persistence.mountPath }} + chmod 0711 {{ .Values.persistence.mountPath }} + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 12 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: {{ .Values.persistence.mountPath }} + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- end }} + {{- end }} + containers: + - name: freeradius + image: {{ include "freeradius.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy | quote }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "st-common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} + {{- else if .Values.command }} + command: {{- include "st-common.tplvalues.render" (dict "value" .Values.command "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "st-common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.args }} + args: {{- include "st-common.tplvalues.render" (dict "value" .Values.args "context" $) | nindent 12 }} + {{- else }} + args: + - -fxx + - -l + - stdout + {{- end }} + env: + {{- if .Values.modsEnabled.sql.enabled }} + - name: FREERADIUS_MODS_SQL_PASSWORD + valueFrom: + secretKeyRef: + {{- if .Values.auth.existingSecretPerPassword }} + name: {{ tpl (include "st-common.secrets.name" (dict "existingSecret" .Values.auth.existingSecretPerPassword.databasePassword "context" $)) $ }} + key: {{ include "st-common.secrets.key" (dict "existingSecret" .Values.auth.existingSecretPerPassword "key" "databasePassword") }} + {{- else }} + name: {{ include "freeradius.database.secretName" . }} + key: {{ include "freeradius.database.secretKey" . }} + {{- end }} + {{- end }} + {{- if .Values.sitesEnabled.status.enabled }} + - name: FREERADIUS_SITES_STATUS_SECRET + valueFrom: + secretKeyRef: + {{- if .Values.auth.existingSecretPerPassword }} + name: {{ tpl (include "st-common.secrets.name" (dict "existingSecret" .Values.auth.existingSecretPerPassword.sitesStatusSecret "context" $)) $ }} + key: {{ include "st-common.secrets.key" (dict "existingSecret" .Values.auth.existingSecretPerPassword "key" "sitesStatusSecret") }} + {{- else }} + name: {{ $globalSecretName }} + key: {{ include "st-common.secrets.key" (dict "existingSecret" .Values.auth.existingSecret "key" "sites-status-secret") }} + {{- end }} + {{- end }} + {{- if .Values.sitesEnabled.tls.enabled }} + - name: FREERADIUS_SITES_TLS_PRIVKEY_PASSWORD + valueFrom: + secretKeyRef: + {{- if .Values.auth.existingSecretPerPassword }} + name: {{ tpl (include "st-common.secrets.name" (dict "existingSecret" .Values.auth.existingSecretPerPassword.sitesTlsPrivKeyPassword "context" $)) $ }} + key: {{ include "st-common.secrets.key" (dict "existingSecret" .Values.auth.existingSecretPerPassword "key" "sitesTlsPrivKeyPassword") }} + {{- else }} + name: {{ $globalSecretName }} + key: {{ include "st-common.secrets.key" (dict "existingSecret" .Values.auth.existingSecret "key" "sites-tls-privkey-password") }} + {{- end }} + {{- end }} + {{- if .Values.extraEnvVars }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + envFrom: + - configMapRef: + name: {{ include "freeradius.names.envvars" . }} + {{- if .Values.extraEnvVarsCM }} + - configMapRef: + name: {{ .Values.extraEnvVarsCM }} + {{- end }} + {{- if .Values.extraEnvVarsSecret }} + - secretRef: + name: {{ .Values.extraEnvVarsSecret }} + {{- end }} + {{- if .Values.lifecycleHooks }} + lifecycle: {{- include "st-common.tplvalues.render" (dict "value" .Values.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + ports: + - name: auth + containerPort: {{ .Values.containerPorts.auth }} + protocol: UDP + - name: acct + containerPort: {{ .Values.containerPorts.acct }} + protocol: UDP + {{- if .Values.sitesEnabled.coa.enabled }} + - name: coa + containerPort: {{ .Values.containerPorts.coa }} + protocol: UDP + {{- end }} + {{- if .Values.tls.enabled }} + - name: radsec + containerPort: {{ .Values.containerPorts.radsec }} + protocol: TCP + {{- end }} + {{- if .Values.sitesEnabled.status.enabled }} + - name: status + containerPort: {{ .Values.containerPorts.status }} + protocol: UDP + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.customStartupProbe }} + startupProbe: {{- include "st-common.tplvalues.render" (dict "value" .Values.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.startupProbe.enabled }} + startupProbe: {{- include "st-common.tplvalues.render" (dict "value" (omit .Values.startupProbe "enabled") "context" $) | nindent 12 }} + exec: + command: + - sh + - -c + - | + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + if [[ ! -f "{{ .Values.persistence.mountPath }}/.user_scripts_initialized" ]]; then + echo "Init scripts still not executed. Skipping check" + exit 1 + fi + {{- end }} + /bin/echo "Message-Authenticator = 0x00" | /usr/bin/radclient 127.0.0.1:${FREERADIUS_SITES_STATUS_PORT} status ${FREERADIUS_SITES_STATUS_SECRET} + {{- end }} + {{- if .Values.customLivenessProbe }} + livenessProbe: {{- include "st-common.tplvalues.render" (dict "value" .Values.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.livenessProbe.enabled }} + livenessProbe: {{- omit .Values.livenessProbe "enabled" | toYaml | nindent 12 }} + exec: + command: + - sh + - -c + - >- + /bin/echo "Message-Authenticator = 0x00" | /usr/bin/radclient 127.0.0.1:${FREERADIUS_SITES_STATUS_PORT} status ${FREERADIUS_SITES_STATUS_SECRET} + {{- end }} + {{- if .Values.customReadinessProbe }} + readinessProbe: {{- include "st-common.tplvalues.render" (dict "value" .Values.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.readinessProbe.enabled }} + readinessProbe: {{- omit .Values.readinessProbe "enabled" | toYaml | nindent 12 }} + exec: + command: + - sh + - -c + - >- + /bin/echo "Message-Authenticator = 0x00" | /usr/bin/radclient 127.0.0.1:${FREERADIUS_SITES_STATUS_PORT} status ${FREERADIUS_SITES_STATUS_SECRET} + {{- end }} + {{- end }} + {{- if .resources }} + resources: {{- include "st-common.tplvalues.render" (dict "value" .resources "context" $) | nindent 12 }} + {{- else if and .resourcesPreset (ne .resourcesPreset "none") }} + resources: {{- include "st-common.resources.preset" (dict "type" .resourcesPreset) | nindent 12 }} + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: {{ default "/startechnica/freeradius" .Values.persistence.mountPath }} + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if or (.Files.Glob "files/radiusd.conf") .Values.configuration .Values.configurationConfigMap }} + - name: freeradius-config + mountPath: /etc/freeradius/radiusd.conf + subPath: radiusd.conf + {{- end }} + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + mountPath: /docker-entrypoint-initdb.d + {{- end }} + {{- if .Values.modsEnabled.sql.enabled }} + - name: freeradius-mods + mountPath: /etc/freeradius/mods-enabled/sql + subPath: sql + {{- end }} + - name: freeradius-sites + mountPath: /etc/freeradius/sites-enabled/default + subPath: default + - name: freeradius-sites + mountPath: /etc/freeradius/sites-enabled/status + subPath: status + {{- if .Values.sitesEnabled.coa.enabled }} + - name: freeradius-sites + mountPath: /etc/freeradius/sites-enabled/coa + subPath: coa + {{- end }} + {{- if .Values.tls.enabled }} + - name: freeradius-sites + mountPath: /etc/freeradius/sites-enabled/tls + subPath: tls + - name: freeradius-tls + mountPath: /opt/startechnica/freeradius/certs + readOnly: true + {{- end }} + {{- if and .Values.modsEnabled.sql.enabled (eq .Values.modsEnabled.sql.dialect "sqlite") }} + - name: freeradius-sqlite + mountPath: {{ .Values.modsEnabled.sql.sqlite.filename | quote }} + {{- end }} + {{- if .Values.modsEnabled.sql.tls.enabled }} + - name: freeradius-sql-tls + mountPath: /opt/startechnica/freeradius/certs + {{- end }} + - name: shared-certs + mountPath: /opt/startechnica/freeradius/shared-certs + readOnly: true + - name: temp + mountPath: /startechnica/freeradius/tmp + {{- if .Values.extraVolumeMounts }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.sidecars }} + {{- include "st-common.tplvalues.render" ( dict "value" .Values.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + - name: freeradius-mods + configMap: + name: {{ printf "%s-mods" (include "st-common.names.fullname" .) }} + - name: freeradius-sites + configMap: + name: {{ printf "%s-sites" (include "st-common.names.fullname" .) }} + - name: temp + emptyDir: {} + - name: shared-certs + emptyDir: {} + - name: data + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ include "freeradius.claimName" . }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if and .Values.modsEnabled.sql.enabled (eq .Values.modsEnabled.sql.dialect "sqlite") }} + - name: freeradius-sqlite + emptyDir: {} + {{- end }} + {{- if .Values.tls.enabled }} + - name: freeradius-tls + secret: + secretName: {{ include "freeradius.tlsSecretName" . }} + {{- end }} + {{- if .Values.modsEnabled.sql.tls.enabled }} + - name: freeradius-sql-tls + secret: + secretName: {{ include "freeradius.sqlTlsSecretName" . }} + items: + - key: tls.crt + path: sql-tls.crt + - key: tls.key + path: sql-tls.key + - key: ca.crt + path: sql-ca.crt + {{- end }} + {{- if or (.Files.Glob "files/radiusd.conf") .Values.configuration .Values.configurationConfigMap }} + - name: freeradius-config + configMap: + name: {{ include "freeradius.configurationCM" . }} + {{- end }} + {{- if or (.Files.Glob "files/docker-entrypoint-initdb.d/*.{sh,sql,sql.gz}") .Values.initdbScriptsConfigMap .Values.initdbScripts }} + - name: custom-init-scripts + configMap: + name: {{ include "freeradius.initdbScriptsCM" . }} + {{- end }} + {{- if .Values.extraVolumes }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/templates/Istio/Gateway.yaml b/templates/Istio/Gateway.yaml new file mode 100644 index 0000000..c1232f8 --- /dev/null +++ b/templates/Istio/Gateway.yaml @@ -0,0 +1,69 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if and .Values.gateway.enabled (not .Values.gateway.existingGateway) }} +{{- if not (eq (include "st-common.capabilities.istioGateway.apiVersion" .) "false") }} +apiVersion: {{ include "st-common.capabilities.istioGateway.apiVersion" . }} +kind: Gateway +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ include "st-common.names.namespace" . }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} + {{- end }} +spec: + selector: + istio.io/gateway-name: {{ default "ingressgateway" .Values.gateway.name }} + servers: + - port: + name: auth + number: {{ .Values.service.ports.auth }} + protocol: UDP + hosts: + - {{ .Values.ingress.hostname }} + {{- range $host := .Values.ingress.extraHosts }} + - {{ $host.name | quote }} + {{- end }} + - port: + name: acct + number: {{ .Values.service.ports.acct }} + protocol: UDP + hosts: + - {{ .Values.ingress.hostname }} + {{- range $host := .Values.ingress.extraHosts }} + - {{ $host.name | quote }} + {{- end }} + - port: + name: coa + number: {{ .Values.service.ports.coa }} + protocol: UDP + hosts: + - {{ .Values.ingress.hostname }} + {{- range $host := .Values.ingress.extraHosts }} + - {{ $host.name | quote }} + {{- end }} + - port: + name: radsec + number: {{ .Values.service.ports.radsec }} + protocol: TLS + hosts: + - {{ .Values.ingress.hostname }} + {{- range $host := .Values.ingress.extraHosts }} + - {{ $host.name | quote }} + {{- end }} + tls: + mode: PASSTHROUGH + {{- if .Values.sitesEnabled.tls.enabled }} + credentialName: {{ include "freeradius.tlsSecretName" . }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/Istio/VirtualService.yaml b/templates/Istio/VirtualService.yaml new file mode 100644 index 0000000..bbbf70b --- /dev/null +++ b/templates/Istio/VirtualService.yaml @@ -0,0 +1,47 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if and .Values.gateway.enabled (not .Values.gateway.existingVirtualService) }} +{{- if not (eq (include "st-common.capabilities.istioVirtualService.apiVersion" .) "false") }} +apiVersion: {{ include "st-common.capabilities.istioVirtualService.apiVersion" . }} +kind: VirtualService +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ include "st-common.names.namespace" . }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: freeradius + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} + {{- end }} +spec: + gateways: + - {{ printf "%s/%s" (include "st-common.names.namespace" .) (include "st-common.names.fullname" .) }} + hosts: + - {{ .Values.ingress.hostname }} + {{- range $host := .Values.ingress.extraHosts }} + - {{ $host | quote }} + {{- end }} + tls: + - match: + - port: {{ .Values.service.ports.radsec }} + sniHosts: + - {{ .Values.ingress.hostname }} + {{- range $host := .Values.ingress.extraHosts }} + - {{ $host | quote }} + {{- end }} + route: + - destination: + # host: {{ printf "%s.%s.svc.%s" (include "st-common.names.fullname" .) (include "st-common.names.namespace" .) .Values.clusterDomain }} + host: {{ printf "%s.%s.svc.cluster.local" (include "st-common.names.fullname" .) (include "st-common.names.namespace" .) }} + port: + number: {{ .Values.service.ports.radsec }} +{{- end }} +{{- end }} diff --git a/templates/NetworkPolicy.yaml b/templates/NetworkPolicy.yaml new file mode 100644 index 0000000..35e544a --- /dev/null +++ b/templates/NetworkPolicy.yaml @@ -0,0 +1,57 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if .Values.networkPolicy.enabled }} +apiVersion: {{ include "st-common.capabilities.networkPolicy.apiVersion" . }} +kind: NetworkPolicy +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: freeradius + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + podSelector: + matchLabels: {{- include "st-common.labels.matchLabels" . | nindent 6 }} + ingress: + - ports: + - port: {{ .Values.containerPorts.auth }} + protocol: UDP + - port: {{ .Values.containerPorts.acct }} + protocol: UDP + {{- if .Values.tls.enabled }} + - port: {{ .Values.containerPorts.radsec }} + protocol: TCP + {{- end }} + {{- if .Values.metrics.enabled }} + - port: {{ .Values.containerPorts.metrics }} + protocol: TCP + {{- end }} + {{- if .Values.sitesEnabled.coa.enabled }} + - port: {{ .Values.containerPorts.coa }} + protocol: UDP + {{- end }} + {{- if .Values.sitesEnabled.status.enabled }} + - port: {{ .Values.containerPorts.status }} + protocol: UDP + {{- end }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ include "st-common.names.fullname" . }}-client: "true" + - podSelector: + matchLabels: {{- include "st-common.labels.matchLabels" . | nindent 14 }} + app.kubernetes.io/component: freeradius + {{- if .Values.networkPolicy.additionalRules }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.networkPolicy.additionalRules "context" $) | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/templates/PersistentVolumeClaim.yaml b/templates/PersistentVolumeClaim.yaml new file mode 100644 index 0000000..0cd0acc --- /dev/null +++ b/templates/PersistentVolumeClaim.yaml @@ -0,0 +1,38 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) -}} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if or .Values.persistence.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.persistence.annotations }} + {{- include "st-common.tplvalues.render" ( dict "value" .Values.persistence.annotations "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} +spec: + accessModes: + {{- if not (empty .Values.persistence.accessModes) }} + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + {{- else }} + - {{ .Values.persistence.accessMode | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- include "st-common.storage.class" (dict "persistence" .Values.persistence "global" .Values.global) | nindent 2 }} +{{- end -}} \ No newline at end of file diff --git a/templates/PodDisruptionBudget.yaml b/templates/PodDisruptionBudget.yaml new file mode 100644 index 0000000..a4b619e --- /dev/null +++ b/templates/PodDisruptionBudget.yaml @@ -0,0 +1,28 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if .Values.podDisruptionBudget.create }} +apiVersion: {{ include "st-common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: {{ include "st-common.labels.matchLabels" . | nindent 6 }} +{{- end }} \ No newline at end of file diff --git a/templates/PrometheusRule.yaml b/templates/PrometheusRule.yaml new file mode 100644 index 0000000..fafd180 --- /dev/null +++ b/templates/PrometheusRule.yaml @@ -0,0 +1,25 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{ if and .Values.metrics.enabled .Values.metrics.prometheusRules.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.metrics.prometheusRules.additionalLabels "context" $) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + groups: + - name: {{ include "st-common.names.fullname" . }} + rules: + {{- toYaml .Values.metrics.prometheusRules.rules | nindent 6 }} +{{ end }} \ No newline at end of file diff --git a/templates/Role.yaml b/templates/Role.yaml new file mode 100644 index 0000000..89bcc15 --- /dev/null +++ b/templates/Role.yaml @@ -0,0 +1,29 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if .Values.rbac.create }} +apiVersion: {{ include "st-common.capabilities.rbac.apiVersion" . }} +kind: Role +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +rules: + - apiGroups: + - "" + resources: + - secrets + - configmaps + verbs: + - get + - list + - watch +{{- end }} \ No newline at end of file diff --git a/templates/RoleBinding.yaml b/templates/RoleBinding.yaml new file mode 100644 index 0000000..1975a59 --- /dev/null +++ b/templates/RoleBinding.yaml @@ -0,0 +1,26 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +apiVersion: {{ include "st-common.capabilities.rbac.apiVersion" . }} +kind: RoleBinding +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +subjects: + - kind: ServiceAccount + name: {{ include "freeradius.serviceAccountName" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "st-common.names.fullname" . }} +{{- end }} \ No newline at end of file diff --git a/templates/Secret/credentials.yaml b/templates/Secret/credentials.yaml new file mode 100644 index 0000000..6618ad5 --- /dev/null +++ b/templates/Secret/credentials.yaml @@ -0,0 +1,38 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if and (not .Values.auth.existingSecret) (not .Values.auth.existingSecretPerPassword) }} +{{- $secretName := include "st-common.secrets.name" (dict "existingSecret" .Values.auth.existingSecret "context" $) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secretName }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: freeradius + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +type: Opaque +data: + {{- if and (not .Values.mariadb.enabled) (not .Values.externalDatabase.existingSecret) }} + database-password: {{ include "st-common.secrets.passwords.manage" (dict "secret" $secretName "key" "database-password" "length" 10 "providedValues" (list "externalDatabase.password") "context" $) }} + {{- end }} + {{- if and (.Values.mariadb.enabled) (not (empty .Values.mariadb.auth.username)) }} + mariadb-password: {{ include "st-common.secrets.passwords.manage" (dict "secret" $secretName "key" "mariadb-password" "providedValues" (list "mariadb.auth.password") "context" $) }} + {{- end }} + {{- if (.Values.sitesEnabled.status.enabled) }} + sites-status-secret: {{ include "st-common.secrets.passwords.manage" (dict "secret" $secretName "key" "sites-status-secret" "length" 10 "providedValues" (list "sitesEnabled.status.secret") "context" $) }} + {{- end }} + {{- if (.Values.sitesEnabled.tls.enabled) }} + sites-tls-privkey-password: {{ include "st-common.secrets.passwords.manage" (dict "secret" $secretName "key" "sites-tls-privkey-password" "length" 10 "providedValues" (list "sitesEnabled.tls.privateKeyPassword") "context" $) }} + {{- end }} + {{- if (.Values.modsEnabled.sql.tls.enabled) }} + mods-sql-tls-privkey-password: {{ include "st-common.secrets.passwords.manage" (dict "secret" $secretName "key" "mods-sql-tls-privkey-password" "length" 10 "providedValues" (list "modsEnabled.sql.tls.privateKeyPassword") "context" $) }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/Secret/sql-tls.yaml b/templates/Secret/sql-tls.yaml new file mode 100644 index 0000000..e49a5e2 --- /dev/null +++ b/templates/Secret/sql-tls.yaml @@ -0,0 +1,30 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if and (include "freeradius.createSqlTlsSecret" .) (not .Values.tls.autoGenerator.certmanager.enabled) }} +{{- $ca := genCA "freeradius-ca" 365 }} +{{- $releaseNamespace := include "st-common.names.namespace" . }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $fullname := include "st-common.names.fullname" . }} +{{- $altNames := list (printf "*.%s.%s.svc.%s" $fullname $releaseNamespace $clusterDomain) (printf "%s.%s.svc" $fullname $releaseNamespace) (printf "%s.%s" $fullname $releaseNamespace) $fullname }} +{{- $crt := genSignedCert $fullname nil $altNames 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "st-common.names.fullname" . }}-sql-tls + namespace: {{ include "st-common.names.namespace" . | quote }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $crt.Cert | b64enc | quote }} + tls.key: {{ $crt.Key | b64enc | quote }} +{{- end }} \ No newline at end of file diff --git a/templates/Secret/tls.yaml b/templates/Secret/tls.yaml new file mode 100644 index 0000000..3b182d5 --- /dev/null +++ b/templates/Secret/tls.yaml @@ -0,0 +1,30 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if and (include "freeradius.createTlsSecret" .) (not .Values.tls.autoGenerator.certmanager.enabled) }} +{{- $ca := genCA "freeradius-ca" 365 }} +{{- $releaseNamespace := include "st-common.names.namespace" . }} +{{- $clusterDomain := .Values.clusterDomain }} +{{- $fullname := include "st-common.names.fullname" . }} +{{- $altNames := list (printf "*.%s.%s.svc.%s" $fullname $releaseNamespace $clusterDomain) (printf "%s.%s.svc" $fullname $releaseNamespace) (printf "%s.%s" $fullname $releaseNamespace) $fullname }} +{{- $crt := genSignedCert $fullname nil $altNames 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "st-common.names.fullname" . }}-tls + namespace: {{ include "st-common.names.namespace" . | quote }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $crt.Cert | b64enc | quote }} + tls.key: {{ $crt.Key | b64enc | quote }} +{{- end }} \ No newline at end of file diff --git a/templates/Service.yaml b/templates/Service.yaml new file mode 100644 index 0000000..7571125 --- /dev/null +++ b/templates/Service.yaml @@ -0,0 +1,98 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +apiVersion: v1 +kind: Service +metadata: + name: {{ include "st-common.names.fullname" . }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: freeradius + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if or .Values.service.annotations .Values.commonAnnotations .Values.metrics.annotations }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.service.annotations }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.service.annotations "context" $) | nindent 4 }} + {{- end }} + {{- if and .Values.metrics.enabled .Values.metrics.annotations }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.metrics.annotations "context" $) | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ default "ClusterIP" .Values.service.type }} + {{- if eq .Values.service.type "LoadBalancer" }} + allocateLoadBalancerNodePorts: {{ eq .Values.service.allocateLoadBalancerNodePorts "true" }} + {{- end }} + {{- if and .Values.service.clusterIP (eq .Values.service.type "ClusterIP") }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if and .Values.service.externalTrafficPolicy (or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort")) }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }} + {{- end }} + ipFamilyPolicy: {{ .Values.service.ipFamilyPolicy }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerClass)) }} + loadBalancerClass: {{ .Values.service.loadBalancerClass }} + {{- end }} + {{- if (and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP))) }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerSourceRanges)) }} + loadBalancerSourceRanges: {{ .Values.service.loadBalancerSourceRanges }} + {{- end }} + {{- if .Values.service.sessionAffinity }} + sessionAffinity: {{ .Values.service.sessionAffinity }} + {{- end }} + {{- if .Values.service.sessionAffinityConfig }} + sessionAffinityConfig: {{- include "st-common.tplvalues.render" (dict "value" .Values.service.sessionAffinityConfig "context" $) | nindent 4 }} + {{- end }} + ports: + - name: udp-auth + port: {{ .Values.service.ports.auth }} + protocol: UDP + targetPort: {{ .Values.containerPorts.auth }} + {{- if (and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) .Values.service.nodePorts.auth) }} + nodePort: {{ coalesce .Values.service.nodePorts.auth .Values.service.nodePort }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + - name: udp-acct + port: {{ .Values.service.ports.acct }} + protocol: UDP + targetPort: {{ .Values.containerPorts.acct }} + {{- if (and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) .Values.service.nodePorts.acct) }} + nodePort: {{ .Values.service.nodePorts.acct }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- if .Values.sitesEnabled.coa.enabled }} + - name: udp-coa + port: {{ .Values.service.ports.coa }} + protocol: UDP + targetPort: {{ .Values.containerPorts.coa }} + {{- if (and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) .Values.service.nodePorts.coa) }} + nodePort: {{ .Values.service.nodePorts.coa }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: tcp-radsec + port: {{ .Values.service.ports.radsec }} + protocol: TCP + targetPort: {{ .Values.containerPorts.radsec }} + {{- if (and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) .Values.service.nodePorts.radsec) }} + nodePort: {{ .Values.service.nodePorts.radsec }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- end }} + selector: {{ include "st-common.labels.matchLabels" . | nindent 4 }} + app.kubernetes.io/component: freeradius +--- \ No newline at end of file diff --git a/templates/ServiceAccount.yaml b/templates/ServiceAccount.yaml new file mode 100644 index 0000000..9e621e5 --- /dev/null +++ b/templates/ServiceAccount.yaml @@ -0,0 +1,27 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "freeradius.serviceAccountName" . }} + namespace: {{ include "st-common.names.namespace" . | quote }} + labels: {{- include "st-common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: freeradius + {{- if .Values.commonLabels }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonLabels "context" $) | nindent 4 }} + {{- end }} + {{- if or .Values.serviceAccount.annotations .Values.commonAnnotations }} + annotations: + {{- if .Values.commonAnnotations }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} + {{- if .Values.serviceAccount.annotations }} + {{- include "st-common.tplvalues.render" (dict "value" .Values.serviceAccount.annotations "context" $) | nindent 4 }} + {{- end }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/templates/_helpers/_databases.tpl b/templates/_helpers/_databases.tpl new file mode 100644 index 0000000..1bb165c --- /dev/null +++ b/templates/_helpers/_databases.tpl @@ -0,0 +1,95 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* Create a default fully qualified app name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). */}} +{{- define "freeradius.mariadb.fullname" -}} + {{- include "st-common.names.dependency.fullname" (dict "chartName" "mariadb" "chartValues" .Values.mariadb "context" $) -}} +{{- end -}} + +{{/* Return the Database hostname */}} +{{- define "freeradius.database.host" -}} +{{- if eq .Values.mariadb.architecture "replication" }} + {{- ternary (include "freeradius.mariadb.fullname" .) .Values.externalDatabase.host .Values.mariadb.enabled -}}-primary +{{- else -}} + {{- ternary (include "freeradius.mariadb.fullname" .) .Values.externalDatabase.host .Values.mariadb.enabled -}} +{{- end -}} +{{- end -}} + +{{/* Return the Database port */}} +{{- define "freeradius.database.port" -}} + {{- ternary "3306" .Values.externalDatabase.port .Values.mariadb.enabled | quote -}} +{{- end -}} + +{{/* Return the Database database name */}} +{{- define "freeradius.database.name" -}} +{{- if .Values.mariadb.enabled }} + {{- if .Values.global.mariadb }} + {{- if .Values.global.mariadb.auth }} + {{- coalesce .Values.global.mariadb.auth.database .Values.mariadb.auth.database -}} + {{- else -}} + {{- .Values.mariadb.auth.database -}} + {{- end -}} + {{- else -}} + {{- .Values.mariadb.auth.database -}} + {{- end -}} +{{- else -}} + {{- .Values.externalDatabase.database -}} +{{- end -}} +{{- end -}} + +{{/* Return the Database user */}} +{{- define "freeradius.database.user" -}} +{{- if .Values.mariadb.enabled }} + {{- if .Values.global.mariadb }} + {{- if .Values.global.mariadb.auth }} + {{- coalesce .Values.global.mariadb.auth.username .Values.mariadb.auth.username -}} + {{- else -}} + {{- .Values.mariadb.auth.username -}} + {{- end -}} + {{- else -}} + {{- .Values.mariadb.auth.username -}} + {{- end -}} +{{- else -}} + {{- .Values.externalDatabase.user -}} +{{- end -}} +{{- end -}} + +{{/* Return the Database encrypted password */}} +{{- define "freeradius.database.secretName" -}} +{{- if .Values.mariadb.enabled }} + {{- if .Values.global.mariadb }} + {{- if .Values.global.mariadb.auth }} + {{- if .Values.global.mariadb.auth.existingSecret }} + {{- tpl .Values.global.mariadb.auth.existingSecret $ -}} + {{- else -}} + {{- default (include "freeradius.mariadb.fullname" .) (tpl .Values.mariadb.auth.existingSecret $) -}} + {{- end -}} + {{- else -}} + {{- default (include "freeradius.mariadb.fullname" .) (tpl .Values.mariadb.auth.existingSecret $) -}} + {{- end -}} + {{- else -}} + {{- default (include "freeradius.mariadb.fullname" .) (tpl .Values.mariadb.auth.existingSecret $) -}} + {{- end -}} +{{- else -}} + {{- default (include "st-common.secrets.name" (dict "existingSecret" .Values.mariadb.auth.existingSecret "context" $)) (tpl .Values.externalDatabase.existingSecret $) -}} +{{- end -}} +{{- end -}} + +{{/* Add environment variables to configure database values */}} +{{- define "freeradius.database.secretKey" -}} +{{- if .Values.mariadb.enabled -}} + {{- print "mariadb-password" -}} +{{- else -}} + {{- if .Values.externalDatabase.existingSecret -}} + {{- if .Values.externalDatabase.existingSecretPasswordKey -}} + {{- printf "%s" .Values.externalDatabase.existingSecretPasswordKey -}} + {{- else -}} + {{- print "database-password" -}} + {{- end -}} + {{- else -}} + {{- print "database-password" -}} + {{- end -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/templates/_helpers/_helpers.tpl b/templates/_helpers/_helpers.tpl new file mode 100644 index 0000000..35ff55e --- /dev/null +++ b/templates/_helpers/_helpers.tpl @@ -0,0 +1,140 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* Create the name of the service account to use */}} +{{- define "freeradius.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} + {{- default (include "st-common.names.fullname" .) .Values.serviceAccount.name }} +{{- else }} + {{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* Return the path to the cert file. */}} +{{- define "freeradius.tlsCert" -}} +{{- if and .Values.tls.enabled .Values.tls.autoGenerated }} + {{- printf "/opt/startechnica/freeradius/certs/tls.crt" -}} +{{- else -}} + {{- printf "/opt/startechnica/freeradius/certs/%s" .Values.tls.certFilename -}} +{{- end -}} +{{- end -}} + +{{/* Return the path to the cert key file. */}} +{{- define "freeradius.tlsCertKey" -}} +{{- if and .Values.tls.enabled .Values.tls.autoGenerated }} + {{- printf "/opt/startechnica/freeradius/certs/tls.key" -}} +{{- else -}} + {{- printf "/opt/startechnica/freeradius/certs/%s" .Values.tls.certKeyFilename -}} +{{- end -}} +{{- end -}} + +{{/* Return the path to the CA cert file. */}} +{{- define "freeradius.tlsCACert" -}} +{{- if and .Values.tls.enabled .Values.tls.autoGenerated }} + {{- printf "/opt/startechnica/freeradius/certs/ca.crt" -}} +{{- else -}} + {{- printf "/opt/startechnica/freeradius/certs/%s" .Values.tls.certCAFilename -}} +{{- end -}} +{{- end -}} + +{{/* Create the name of the SSL certificate to use */}} +{{- define "freeradius.tlsSecretName" -}} +{{- if .Values.tls.certificatesSecret }} + {{ .Values.tls.certificatesSecret }} +{{- else }} + {{- default (printf "%s-tls" (include "st-common.names.fullname" .)) }} +{{- end }} +{{- end -}} + +{{/* Return true if a TLS secret object should be created */}} +{{- define "freeradius.createTlsSecret" -}} +{{- if and .Values.tls.enabled .Values.tls.autoGenerated (not .Values.tls.certificatesSecret) }} + {{- true }} +{{- end }} +{{- end -}} + +{{/* Validate values of FreeRADIUS - Auth TLS enabled */}} +{{- define "freeradius.validateValues.tls" -}} +{{- if and .Values.tls.enabled (not .Values.tls.autoGenerated) (not .Values.tls.certificatesSecret) }} +freeradius: tls.enabled + In order to enable TLS, you also need to provide + an existing secret containing the Keystore and Truststore or + enable auto-generated certificates. +{{- end }} +{{- end -}} + +{{/* Return the path to the SQL cert file. */}} +{{- define "freeradius.sqlTlsCert" -}} +{{- if and .Values.modsEnabled.sql.tls.enabled }} + {{- if .Values.modsEnabled.sql.tls.autoGenerated }} + {{- printf "/opt/startechnica/freeradius/certs/sql-tls.crt" -}} + {{- else if not (empty .Values.modsEnabled.sql.tls.certFilename) }} + {{- printf "/opt/startechnica/freeradius/certs/%s" .Values.modsEnabled.sql.tls.certFilename -}} + {{- end }} +{{- else }} + {{- printf "" -}} +{{- end }} +{{- end -}} + +{{/* Return the path to the SQL cert key file. */}} +{{- define "freeradius.sqlTlsCertKey" -}} +{{- if and .Values.modsEnabled.sql.tls.enabled }} + {{- if .Values.modsEnabled.sql.tls.autoGenerated }} + {{- printf "/opt/startechnica/freeradius/certs/sql-tls.key" -}} + {{- else if not (empty .Values.modsEnabled.sql.tls.certKeyFilename) }} + {{- printf "/opt/startechnica/freeradius/certs/%s" .Values.modsEnabled.sql.tls.certKeyFilename -}} + {{- end }} +{{- else }} + {{- printf "" -}} +{{- end }} +{{- end -}} + +{{/* Return the path to the SQL CA cert file. */}} +{{- define "freeradius.sqlTlsCACert" -}} +{{- if and .Values.modsEnabled.sql.tls.enabled }} + {{- if .Values.modsEnabled.sql.tls.autoGenerated }} + {{- printf "/opt/startechnica/freeradius/certs/sql-ca.crt" -}} + {{- else if not (empty .Values.modsEnabled.sql.tls.certCAFilename)}} + {{- printf "/opt/startechnica/freeradius/certs/%s" .Values.modsEnabled.sql.tls.certCAFilename -}} + {{- end }} +{{- else }} + {{- printf "" -}} +{{- end }} +{{- end -}} + +{{/* Create the name of the secret for SQL SSL certificate to use */}} +{{- define "freeradius.sqlTlsSecretName" -}} +{{- if .Values.modsEnabled.sql.tls.certificatesSecret }} + {{ .Values.modsEnabled.sql.tls.certificatesSecret }} +{{- else }} + {{- default (printf "%s-sql-tls" (include "st-common.names.fullname" .)) }} +{{- end }} +{{- end -}} + +{{/* Return true if a TLS secret object should be created */}} +{{- define "freeradius.createSqlTlsSecret" -}} +{{- if and .Values.modsEnabled.sql.tls.enabled .Values.modsEnabled.sql.tls.autoGenerated (not .Values.modsEnabled.sql.tls.certificatesSecret) }} + {{- true }} +{{- end }} +{{- end -}} + +{{/* Get the configuration ConfigMap name. */}} +{{- define "freeradius.configurationCM" -}} +{{- if .Values.configurationConfigMap -}} + {{- printf "%s" (tpl .Values.configurationConfigMap $) -}} +{{- else -}} + {{- printf "%s-configuration" (include "st-common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + +{{/* Get the initialization scripts ConfigMap name. */}} +{{- define "freeradius.initdbScriptsCM" -}} +{{- if .Values.initdbScriptsConfigMap -}} + {{- printf "%s" .Values.initdbScriptsConfigMap -}} +{{- else -}} + {{- printf "%s-init-scripts" (include "st-common.names.fullname" .) -}} +{{- end -}} +{{- end -}} + diff --git a/templates/_helpers/_images.tpl b/templates/_helpers/_images.tpl new file mode 100644 index 0000000..4d9840b --- /dev/null +++ b/templates/_helpers/_images.tpl @@ -0,0 +1,14 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* Return the proper FreeRADIUS image name */}} +{{- define "freeradius.image" -}} + {{ include "st-common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} +{{- end -}} + +{{/* Return the proper Docker Image Registry Secret Names */}} +{{- define "freeradius.imagePullSecrets" -}} + {{- include "st-common.images.pullSecrets" (dict "images" (list .Values.image .Values.volumePermissions.image .Values.metrics.image) "global" .Values.global) -}} +{{- end -}} \ No newline at end of file diff --git a/templates/_helpers/_names.tpl b/templates/_helpers/_names.tpl new file mode 100644 index 0000000..e4c9bec --- /dev/null +++ b/templates/_helpers/_names.tpl @@ -0,0 +1,10 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* vim: set filetype=mustache: */}} + +{{- define "freeradius.names.envvars" -}} +{{- printf "%s-envvars" (include "st-common.names.fullname" .) -}} +{{- end -}} \ No newline at end of file diff --git a/templates/_helpers/_volumes.tpl b/templates/_helpers/_volumes.tpl new file mode 100644 index 0000000..d636769 --- /dev/null +++ b/templates/_helpers/_volumes.tpl @@ -0,0 +1,18 @@ +{{- /* +Copyright (c) 2025 Firmansyah Nainggolan. All Rights Reserved. +SPDX-License-Identifier: APACHE-2.0 +*/}} + +{{/* Return the FreeRADIUS PVC name. */}} +{{- define "freeradius.claimName" -}} +{{- if .Values.persistence.existingClaim }} + {{- printf "%s" (tpl .Values.persistence.existingClaim $) -}} +{{- else }} + {{- printf "%s" (include "st-common.names.fullname" .) -}} +{{- end }} +{{- end -}} + +{{/* Return the proper image name (for the init container volume-permissions image) */}} +{{- define "freeradius.volumePermissions.image" -}} + {{ include "st-common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} +{{- end -}} \ No newline at end of file diff --git a/values-test.yaml b/values-test.yaml new file mode 100644 index 0000000..059a3c5 --- /dev/null +++ b/values-test.yaml @@ -0,0 +1,44 @@ +persistence: + enabled: true +# storageClass: + +service: + type: LoadBalancer + externalTrafficPolicy: Local + ipFamilyPolicy: PreferDualStack + +modsEnabled: + sql: + enabled: true + dialect: mysql + +externalDatabase: + # host: mariadb-infra-mariadb-galera.mariadb-infra.svc + host: mariadb-primary.mariadb.svc + port: 3306 + user: radius_user + database: radiusdb + password: "aserfdertg" + +sitesEnabled: + coa: + enabled: true + tls: + enabled: true + +tls: + enabled: true + autoGenerated: true + +# updateStrategy: +# type: Recreate + +volumePermissions: + enabled: true + +gateway: + enabled: true + dedicated: false + gatewayApi: false + name: "freeradius" + namespace: "istio-ingress" \ No newline at end of file diff --git a/values.yaml b/values.yaml new file mode 100644 index 0000000..62c1dc7 --- /dev/null +++ b/values.yaml @@ -0,0 +1,985 @@ +## @section Global parameters + +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry, imagePullSecrets and storageClass + +## @param global.imageRegistry Global Docker image registry +## @param global.imagePullSecrets Global Docker registry secret names as an array +## @param global.storageClass Global StorageClass for Persistent Volume(s) +## +global: + imageRegistry: "" + ## E.g. + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## + imagePullSecrets: [] + storageClass: "" + +## @section Common parameters + +## @param kubeVersion Force target Kubernetes version (using Helm capabilities if not set) +## +kubeVersion: "" +## @param nameOverride String to partially override freeradius.fullname +## +nameOverride: "" +## @param namespaceOverride String to partially override freeradius.namespace +## +namespaceOverride: "" +## @param fullnameOverride String to fully override adminer.fullname +## +fullnameOverride: "" +## @param commonLabels Labels to add to all deployed objects +## +commonLabels: {} +## @param commonAnnotations Annotations to add to all deployed objects +## +commonAnnotations: {} +## @param clusterDomain Default Kubernetes cluster domain +## +clusterDomain: cluster.local +## @param extraDeploy Array of extra objects to deploy with the release +## +extraDeploy: [] +## Enable diagnostic mode in the deployment +## +diagnosticMode: + ## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden) + ## + enabled: false + ## @param diagnosticMode.command Command to override all containers in the deployment + ## + command: + - sleep + ## @param diagnosticMode.args Args to override all containers in the deployment + ## + args: + - infinity + +## @section FreeRADIUS Image parameters + +## FreeRADIUS image +## ref: https://hub.docker.com/r/freeradius/freeradius-server/tags +## @param image.registry FreeRADIUS image registry +## @param image.repository FreeRADIUS image repository +## @param image.tag FreeRADIUS image tag (immutable tags are recommended) +## @param image.pullPolicy FreeRADIUS image pull policy +## @param image.pullSecrets Specify docker-registry secret names as an array +## @param image.debug Specify if debug logs should be enabled +## +image: + registry: docker.io + repository: freeradius/freeradius-server + tag: "3.2.7" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets (secrets must be manually created in the namespace) + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Set to true if you would like to see extra information on logs + ## It turns BASH and/or NAMI debugging in the image + ## + debug: false + +## @param architecture FreeRADIUS architecture (`standalone` or `replication`) +## +architecture: standalone + +auth: + ## @param auth.createClientUser Create client user on boot + ## + createClientUser: true + ## @param auth.clientUser FreeRADIUS administrator user + ## + clientUser: user + ## @param auth.clientPassword FreeRADIUS administrator password for the new user + ## + clientUserPassword: "" + ## @param auth.existingSecret An already existing secret containing auth info + ## e.g: + ## existingSecret: + ## name: mySecret + ## keyMapping: + ## client-user-password: myPasswordKey + ## + existingSecret: "" + ## @param auth.existingSecretPerPassword Override `existingSecret` and other secret values + ## e.g: + ## existingSecretPerPassword: + ## keyMapping: + ## clientUserPassword: FREERADIUS_ADMIN_PASSWORD + ## databasePassword: password + ## databasePassword: + ## name: freeradius.pocwatt-freeradius-cluster.credentials + ## + existingSecretPerPassword: {} + +## @param configuration FreeRADIUS Configuration. Auto-generated based on other parameters when not specified +## Specify content for keycloak.conf +## NOTE: This will override configuring FreeRADIUS based on environment variables (including those set by the chart) +## The radiusd.conf is auto-generated based on other parameters when this parameter is not specified +## +## Example: +## configuration: |- +## foo: bar +## baz: +## +configuration: "" +## @param configurationConfigMap ConfigMap with the FreeRADIUS configuration files (Note: Overrides `radiusdConfiguration`). The value is evaluated as a template. +## +configurationConfigMap: "" +## @param existingConfigmap Name of existing ConfigMap with FreeRADIUS configuration +## NOTE: When it's set the configuration parameter is ignored +## +existingConfigmap: "" +## @param extraStartupArgs Extra default startup args +## +extraStartupArgs: "" +## initdb scripts +## @param initdbScripts Specify dictionary of scripts to be run at first boot +## Alternatively, you can put your scripts under the files/docker-entrypoint-initdb.d directory +## e.g: +## initdbScripts: +## my_init_script.sh: | +## #!/bin/sh +## echo "Do something." +## +initdbScripts: {} +## @param initdbScriptsConfigMap ConfigMap with the initdb scripts (Note: Overrides `initdbScripts`) +## +initdbScriptsConfigMap: "" +## @param primary.command Override default container command on FreeRADIUS container(s) (useful when using custom images) +## +command: [] +## @param primary.args Override default container args on FreeRADIUS container(s) (useful when using custom images) +## +args: [] +## @param primary.lifecycleHooks for the FreeRADIUS container(s) to automate configuration before or after startup +## +lifecycleHooks: {} +## @param primary.hostAliases Add deployment host aliases +## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ +## +hostAliases: [] +## @param primary.configuration [string] FreeRADIUS configuration to be injected as ConfigMap +## ref: https://mysql.com/kb/en/mysql/configuring-mysql-with-mycnf/#example-of-configuration-file +## + +## @section FreeRADIUS Deployment parameters + +## @param replicaCount Desired number of cluster nodes +## +replicaCount: 1 +## @param updateStrategy.type updateStrategy for FreeRADIUS Master StatefulSet +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies +## +updateStrategy: + type: RollingUpdate +## @param podLabels Extra labels for FreeRADIUS pods +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +## +podLabels: {} +## @param podAnnotations Annotations for FreeRADIUS pods +## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +## +podAnnotations: {} +## @param podAffinityPreset Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` +## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity +## +podAffinityPreset: "" +## @param podAntiAffinityPreset Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity +## +podAntiAffinityPreset: soft +## Node affinity preset +## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity +## +nodeAffinityPreset: + ## @param nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param nodeAffinityPreset.key Node label key to match. Ignored if `affinity` is set. + ## E.g. + ## key: "kubernetes.io/e2e-az-name" + ## + key: "" + ## @param nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set. + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + +## @param affinity Affinity for FreeRADIUS pods assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +## Note: podAffinityPreset, podAntiAffinityPreset, and nodeAffinityPreset will be ignored when it's set +## +affinity: {} +## @param nodeSelector Node labels for FreeRADIUS pods assignment +## Ref: https://kubernetes.io/docs/user-guide/node-selection/ +## +nodeSelector: {} +## @param tolerations Tolerations for FreeRADIUS pods assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +## +tolerations: [] +## @param topologySpreadConstraints Topology Spread Constraints for FreeRADIUS pods assignment +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ +## E.g. +## topologySpreadConstraints: +## - maxSkew: 1 +## topologyKey: topology.kubernetes.io/zone +## whenUnsatisfiable: DoNotSchedule +## +topologySpreadConstraints: {} + +## @param priorityClassName Priority class for FreeRADIUS pods assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +## +priorityClassName: "" +## @param schedulerName Name of the k8s scheduler (other than default) +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +schedulerName: "" +## @param podManagementPolicy podManagementPolicy to manage scaling operation of FreeRADIUS pods +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies +## +podManagementPolicy: "" + +## @param containerPorts.auth FreeRADIUS Auth container port +## @param containerPorts.acct FreeRADIUS Accounting container port +## @param containerPorts.status FreeRADIUS Status HTTP container port +## +containerPorts: + auth: 1812 + acct: 1813 + coa: 3799 + radsec: 2083 + status: 18121 +## FreeRADIUS Pod security context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod +## @param podSecurityContext.enabled Enable security context for FreeRADIUS pods +## @param podSecurityContext.fsGroup Group ID for the mounted volumes' filesystem +## +podSecurityContext: + enabled: false + fsGroup: 101 + runAsUser: 101 +## FreeRADIUS container security context +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container +## @param containerSecurityContext.enabled FreeRADIUS container securityContext +## @param containerSecurityContext.runAsUser User ID for the FreeRADIUS container +## @param containerSecurityContext.runAsNonRoot Set Controller container's Security Context runAsNonRoot +## +containerSecurityContext: + enabled: true + allowPrivilegeEscalation: false + capabilities: + add: + - SYS_PTRACE + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsUser: 101 + runAsNonRoot: true + +## Resource requests and limits +## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ +## We usually recommend not to specify default resources and to leave this as a conscious +## choice for the user. This also increases chances charts run on environments with little +## resources, such as Minikube. If you do want to specify resources, uncomment the following +## lines, adjust them as necessary, and remove the curly braces after 'resources:'. +## @param resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production). +## More information: https://github.com/startechnica/apps/blob/main/charts/common/templates/_resources.tpl#L15 +## +resourcesPreset: "nano" +## @param resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) +## Example: +## resources: +## requests: +## cpu: 2 +## memory: 512Mi +## limits: +## cpu: 3 +## memory: 1024Mi +## +resources: {} + +## Configure extra options for FreeRADIUS containers' liveness, readiness and startup probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +## @param startupProbe.enabled Enable startupProbe +## @param startupProbe.initialDelaySeconds Initial delay seconds for startupProbe +## @param startupProbe.periodSeconds Period seconds for startupProbe +## @param startupProbe.timeoutSeconds Timeout seconds for startupProbe +## @param startupProbe.failureThreshold Failure threshold for startupProbe +## @param startupProbe.successThreshold Success threshold for startupProbe +## +startupProbe: + enabled: false + initialDelaySeconds: 120 + periodSeconds: 15 + timeoutSeconds: 5 + failureThreshold: 10 + successThreshold: 1 +## Configure extra options for liveness probe +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes +## @param livenessProbe.enabled Enable livenessProbe +## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe +## @param livenessProbe.periodSeconds Period seconds for livenessProbe +## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe +## @param livenessProbe.failureThreshold Failure threshold for livenessProbe +## @param livenessProbe.successThreshold Success threshold for livenessProbe +## +livenessProbe: + enabled: true + initialDelaySeconds: 120 + periodSeconds: 60 + timeoutSeconds: 2 + failureThreshold: 3 + successThreshold: 1 +## @param readinessProbe.enabled Enable readinessProbe +## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe +## @param readinessProbe.periodSeconds Period seconds for readinessProbe +## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe +## @param readinessProbe.failureThreshold Failure threshold for readinessProbe +## @param readinessProbe.successThreshold Success threshold for readinessProbe +## +readinessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 +## @param customStartupProbe Override default startup probe for FreeRADIUS containers +## +customStartupProbe: {} +## @param customLivenessProbe Override default liveness probe for FreeRADIUS containers +## +customLivenessProbe: {} +## @param customReadinessProbe Override default readiness probe for FreeRADIUS containers +## +customReadinessProbe: {} +## @param startupWaitOptions Override default builtin startup wait check options for FreeRADIUS containers +## `bitnami/mariadb` Docker image has built-in startup check mechanism, +## which periodically checks if FreeRADIUS service has started up and stops it +## if all checks have failed after X tries. Use these to control these checks. +## ref: https://github.com/bitnami/bitnami-docker-mariadb/pull/240 +## Example (with default options): +## startupWaitOptions: +## retries: 300 +## waitTime: 2 +## +startupWaitOptions: {} +## @param extraFlags FreeRADIUS additional command line flags +## Can be used to specify command line flags, for example: +## E.g. +## extraFlags: "--max-connect-errors=1000 --max_connections=155" +## +extraFlags: "" +## @param extraEnvVars Extra environment variables to be set on FreeRADIUS containers +## E.g. +## extraEnvVars: +## - name: TZ +## value: "Europe/Paris" +## +extraEnvVars: [] +## @param extraEnvVarsCM Name of existing ConfigMap containing extra env vars for FreeRADIUS containers +## +extraEnvVarsCM: "" +## @param extraEnvVarsSecret Name of existing Secret containing extra env vars for FreeRADIUS containers +## +extraEnvVarsSecret: "" + +## @section Persistence Parameters + +## Persistence Parameters +## ref: https://kubernetes.io/docs/user-guide/persistent-volumes/ +## +persistence: + ## @param persistence.enabled Enable persistence on FreeRADIUS replicas using a `PersistentVolumeClaim` + ## + enabled: false + ## @param persistence.existingClaim Name of an existing `PersistentVolumeClaim` for FreeRADIUS primary replicas + ## NOTE: When it's set the rest of persistence parameters are ignored + ## + existingClaim: "" + ## @param persistence.subPath Subdirectory of the volume to mount at + ## + subPath: "" + ## @param persistence.mountPath Path to mount the volume at + ## + mountPath: /startechnica/freeradius + ## @param persistence.storageClass FreeRADIUS persistent volume storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + storageClass: "" + ## @param persistence.annotations FreeRADIUS persistent volume claim annotations + ## + annotations: {} + ## @param persistence.accessModes FreeRADIUS persistent volume access Modes + ## + accessModes: + - ReadWriteOnce + ## @param persistence.size FreeRADIUS persistent volume size + ## + size: 8Gi + ## @param persistence.selector Selector to match an existing Persistent Volume + ## selector: + ## matchLabels: + ## app: my-app + ## + selector: {} + +## 'volumePermissions' init container parameters +## Changes the owner and group of the persistent volume mount point to runAsUser:fsGroup values +## based on the podSecurityContext/containerSecurityContext parameters +## +volumePermissions: + ## @param volumePermissions.enabled Enable init container that changes the owner/group of the PV mount point to `runAsUser:fsGroup` + ## + enabled: false + ## Bitnami Shell image + ## ref: https://hub.docker.com/r/bitnami/bitnami-shell/tags/ + ## @param volumePermissions.image.registry Bitnami Shell image registry + ## @param volumePermissions.image.repository Bitnami Shell image repository + ## @param volumePermissions.image.tag Bitnami Shell image tag (immutable tags are recommended) + ## @param volumePermissions.image.pullPolicy Bitnami Shell image pull policy + ## @param volumePermissions.image.pullSecrets Bitnami Shell image pull secrets + ## + image: + registry: docker.io + repository: bitnami/os-shell + tag: "11" + digest: "" + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Init container's resource requests and limits + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## @param volumePermissions.resources.limits The resources limits for the init container + ## @param volumePermissions.resources.requests The requested resources for the init container + ## + resources: + limits: {} + requests: {} + ## Init container Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param volumePermissions.securityContext.runAsUser Set init container's Security Context runAsUser + ## NOTE: when runAsUser is set to special value "auto", init container will try to chown the + ## data folder to auto-determined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic user ids (and 0 is not allowed) + ## + securityContext: + runAsUser: 0 + +## @param extraVolumes Optionally specify extra list of additional volumes to the FreeRADIUS pod(s) +## +extraVolumes: [] +## @param extraVolumeMounts Optionally specify extra list of additional volumeMounts for the FreeRADIUS container(s) +## +extraVolumeMounts: [] +## @param initContainers Add additional init containers for the FreeRADIUS pod(s) +## +initContainers: [] +## @param sidecars Add additional sidecar containers for the FreeRADIUS pod(s) +## +sidecars: [] + +## @section Traffic Exposure Parameters + +## FreeRADIUS service parameters +## +service: + ## @param service.type FreeRADIUS Kubernetes service type + ## + type: ClusterIP + ## @param service.ports.auth FreeRADIUS Kubernetes service port + ## + ports: + auth: 1812 + acct: 1813 + coa: 3799 + radsec: 2083 + status: 18121 + ## @param service.nodePorts.mysql FreeRADIUS Kubernetes service node port + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + ## + nodePorts: + auth: "" + acct: "" + coa: "" + radsec: "" + status: "" + ## @param service.clusterIP FreeRADIUS Kubernetes service clusterIP IP + ## + clusterIP: "" + ## @param service.loadBalancerIP FreeRADIUS loadBalancerIP if service type is `LoadBalancer` + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + loadBalancerIP: "" + ## @param service.ipFamilyPolicy FreeRADIUS Kubernetes service ipFamilyPolicy policy + ## + ipFamilyPolicy: SingleStack + ## @param service.externalTrafficPolicy Enable client source IP preservation + ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + ## + externalTrafficPolicy: Cluster + ## @param service.allocateLoadBalancerNodePorts Allow users to disable node ports for Service Type=LoadBalancer. This is useful for + ## bare metal / on-prem environments that rely on VIP based LB implementations. + ## ref https://kubernetes.io/docs/concepts/services-networking/service/#load-balancer-nodeport-allocation + ## + allocateLoadBalancerNodePorts: "false" + ## @param service.loadBalancerClass Enables to use a load balancer implementation other than the cloud provider default. + ## https://kubernetes.io/docs/concepts/services-networking/service/#load-balancer-class + ## + loadBalancerClass: "" + ## @param service.loadBalancerSourceRanges Address that are allowed when FreeRADIUS service is LoadBalancer + ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## E.g. + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + loadBalancerSourceRanges: [] + ## @param service.extraPorts Extra ports to expose (normally used with the `sidecar` value) + ## + extraPorts: [] + ## @param service.annotations Provide any additional annotations which may be required + ## + annotations: {} + ## @param service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" + ## If "ClientIP", consecutive client requests will be directed to the same Pod + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + ## + sessionAffinity: None + ## @param service.sessionAffinityConfig Additional settings for the sessionAffinity + ## sessionAffinityConfig: + ## clientIP: + ## timeoutSeconds: 300 + sessionAffinityConfig: {} +## Configure the ingress resource that allows you to access the FreeRADIUS installation +## ref: https://kubernetes.io/docs/user-guide/ingress/ +## +ingress: + ## @param ingress.enabled Enable ingress record generation for FreeRADIUS + ## + enabled: false + ## @param ingress.pathType Ingress path type + ## + pathType: ImplementationSpecific + ## @param ingress.apiVersion Force Ingress API version (automatically detected if not set) + ## + apiVersion: "" + ## @param ingress.hostname Default host for the ingress record + ## + hostname: freeradius.local + ## @param ingress.path Default path for the ingress record + ## NOTE: You may need to set this to '/*' in order to use this with ALB ingress controllers + ## + path: / + ## @param ingress.annotations Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations. + ## For a full list of possible ingress annotations, please see + ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md + ## Use this parameter to set the required annotations for cert-manager, see + ## ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations + ## + ## e.g: + ## annotations: + ## kubernetes.io/ingress.class: nginx + ## cert-manager.io/cluster-issuer: cluster-issuer-name + ## + annotations: {} + ## @param ingress.tls Enable TLS configuration for the host defined at `ingress.hostname` parameter + ## TLS certificates will be retrieved from a TLS secret with name: `{{- printf "%s-tls" .Values.ingress.hostname }}` + ## You can: + ## - Use the `ingress.secrets` parameter to create this TLS secret + ## - Rely on cert-manager to create it by setting the corresponding annotations + ## - Rely on Helm to create self-signed certificates by setting `ingress.selfSigned=true` + ## + tls: false + ## DEPRECATED: Use ingress.annotations instead of ingress.certManager + ## certManager: false + ## + + ## @param ingress.selfSigned Create a TLS secret for this ingress record using self-signed certificates generated by Helm + ## + selfSigned: false + ## @param ingress.extraHosts An array with additional hostname(s) to be covered with the ingress record + ## e.g: + ## extraHosts: + ## - name: freeradius.local + ## path: / + ## + extraHosts: [] + ## @param ingress.extraPaths An array with additional arbitrary paths that may need to be added to the ingress under the main host + ## e.g: + ## extraPaths: + ## - path: /* + ## backend: + ## serviceName: ssl-redirect + ## servicePort: use-annotation + ## + extraPaths: [] + ## @param ingress.extraTls TLS configuration for additional hostname(s) to be covered with this ingress record + ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls + ## e.g: + ## extraTls: + ## - hosts: + ## - freeradius.local + ## secretName: freeradius.local-tls + ## + extraTls: [] + ## @param ingress.secrets Custom TLS certificates as secrets + ## NOTE: 'key' and 'certificate' are expected in PEM format + ## NOTE: 'name' should line up with a 'secretName' set further up + ## If it is not set and you're using cert-manager, this is unneeded, as it will create a secret for you with valid certificates + ## If it is not set and you're NOT using cert-manager either, self-signed certificates will be created valid for 365 days + ## It is also possible to create and manage the certificates outside of this helm chart + ## Please see README.md for more information + ## e.g: + ## secrets: + ## - name: freeradius.local-tls + ## key: |- + ## -----BEGIN RSA PRIVATE KEY----- + ## ... + ## -----END RSA PRIVATE KEY----- + ## certificate: |- + ## -----BEGIN CERTIFICATE----- + ## ... + ## -----END CERTIFICATE----- + ## + secrets: [] + ## @param ingress.ingressClassName IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) + ## This is supported in Kubernetes 1.18+ and required if you have more than one IngressClass marked as the default for your cluster . + ## ref: https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/ + ## + ingressClassName: "" + ## @param ingress.extraRules Additional rules to be covered with this ingress record + ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-rules + ## e.g: + ## extraRules: + ## - host: example.local + ## http: + ## path: / + ## backend: + ## service: + ## name: example-svc + ## port: + ## name: http + ## + extraRules: [] + +## @param revisionHistoryLimit Maximum number of revisions that will be maintained in the Deployment +## +revisionHistoryLimit: 3 + +## @section RBAC parameter +# + +## Specifies whether a ServiceAccount should be created +## +serviceAccount: + ## @param serviceAccount.create Enable the creation of a ServiceAccount for Adminer pods + ## + create: true + ## @param serviceAccount.name Name of the created ServiceAccount + ## If not set and create is true, a name is generated using the fullname template + ## + name: "" + ## @param serviceAccount.automountServiceAccountToken Auto-mount the service account token in the pod + ## + automountServiceAccountToken: false + ## @param serviceAccount.annotations Additional custom annotations for the ServiceAccount + ## + annotations: {} +## Role Based Access +## Ref: https://kubernetes.io/docs/admin/authorization/rbac/ +## +rbac: + ## @param rbac.create Specify whether RBAC resources should be created and used + ## + create: false + ## @param rbac.rules Custom RBAC rules + ## Example: + ## rules: + ## - apiGroups: + ## - "" + ## resources: + ## - pods + ## verbs: + ## - get + ## - list + ## + rules: [] + +## Network Policy configuration +## ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ +## +networkPolicy: + ## @param networkPolicy.enabled Enable the default NetworkPolicy policy + ## + enabled: false + ## @param networkPolicy.allowExternal Don't require client label for connections + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to the ports Keycloak is listening + ## on. When true, Keycloak will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param networkPolicy.additionalRules Additional NetworkPolicy rules + ## Note that all rules are OR-ed. + ## Example: + ## additionalRules: + ## - matchLabels: + ## - role: frontend + ## - matchExpressions: + ## - key: role + ## operator: In + ## values: + ## - frontend + ## + additionalRules: {} + +## Pod disruption budget configuration +## +podDisruptionBudget: + ## @param podDisruptionBudget.create Specifies whether a Pod disruption budget should be created + ## + create: false + ## @param podDisruptionBudget.minAvailable Minimum number / percentage of pods that should remain scheduled + ## + minAvailable: 1 + ## @param podDisruptionBudget.maxUnavailable Maximum number / percentage of pods that may be made unavailable + ## + maxUnavailable: "" + +## MariaDB chart configuration +## ref: https://github.com/bitnami/charts/blob/master/bitnami/mariadb/values.yaml +## @param mariadb.enabled Switch to enable or disable the MariaDB helm chart +## @param mariadb.auth.username Name for a custom user to create +## @param mariadb.auth.password Password for the custom user to create +## @param mariadb.auth.database Name for a custom database to create +## @param mariadb.auth.existingSecret Name of existing secret to use for MariaDB credentials +## @param mariadb.architecture MariaDB architecture (`standalone` or `replication`) +## +mariadb: + enabled: false + auth: + username: freeradius_user + password: "" + database: freeradius_db + existingSecret: "" + architecture: standalone + +## External Database configuration +## All of these values are only used when mariadb.enabled is set to false +## @param externalDatabase.host Database host +## @param externalDatabase.port Database port number +## @param externalDatabase.user Non-root username for FreeRADIUS +## @param externalDatabase.password Password for the non-root username for FreeRADIUS +## @param externalDatabase.database FreeRADIUS database name +## @param externalDatabase.existingSecret Name of an existing secret resource containing the database credentials +## @param externalDatabase.existingSecretPasswordKey Name of an existing secret key containing the database credentials +## +externalDatabase: + host: "" + port: 3306 + user: freeradius_user + database: freeradius_db + password: "" + existingSecret: "" + existingSecretPasswordKey: "" + +modsEnabled: + sql: + enabled: true + dialect: mysql + table: + acct1: radacct + acct2: radacct + authcheck: radcheck + authreply: radreply + client: nas + groupcheck: radgroupcheck + groupreply: radgroupreply + postauth: radpostauth + usergroup: radusergroup + ## @param modsEnabled.sql.groupAttribute The group attribute specific to this instance of rlm_sql + ## + groupAttribute: SQL-Group + ## @param modsEnabled.sql.readClients Set to 'true' to read radius clients from the database ('nas' table) + ## + readClients: true + ## @param modsEnabled.sql.tls.enabled + ## @param modsEnabled.sql.tls.autoGenerated Generate automatically self-signed SQL TLS certificates + ## @param modsEnabled.sql.tls.certificatesSecret + ## @param modsEnabled.sql.tls.certFilename + ## @param modsEnabled.sql.tls.certKeyFilename + ## @param modsEnabled.sql.tls.certCAFilename + ## @param modsEnabled.sql.tls.existingTlsSecret + ## @param modsEnabled.sql.tls.privateKeyPassword + ## + tls: + enabled: false + ciphers: "" + autoGenerated: true + certificatesSecret: "" + certFilename: "" + certKeyFilename: "" + certCAFilename: "" + existingTlsSecret: "" + privateKeyPassword: whatever + + ## @param modsEnabled.sql.sqllite.filename + ## @param modsEnabled.sql.sqllite.busyTimeout + ## + sqlite: + filename: /startechnica/freeradius/freeradius.db + busyTimeout: "200" + +sitesEnabled: + coa: + enabled: false + status: + enabled: true + listen: 127.0.0.1 + secret: adminsecret + tls: + ## @param sitesEnabled.tls.enabled Enable TLS support for radsec traffic + ## + enabled: false + privateKeyPassword: "" + cipher: "DEFAULT" + +clients: + localhost: + ipv4addr: "127.0.0.1" + ipv6addr: "" + proto: udp + secret: password + nasType: other + virtualServer: default + coaServer: coa + limit: + maxConnections: 16 + lifetime: 0 + idleTimeout: 30 + existingConfigMapName: "" + +tls: + ## @param tls.enabled Enable TLS support for FreeRADIUS + ## + enabled: false + ## @param tls.autoGenerated Generate automatically self-signed TLS certificates + ## + autoGenerated: true + autoGenerator: + certmanager: + enabled: false + issuerKind: ClusterIssuer + issuerName: selfsigned-issuer + ## @param tls.certificatesSecret Name of the secret that contains the certificates + ## + certificatesSecret: "" + ## @param tls.certFilename Certificate filename + ## + certFilename: "" + ## @param tls.certKeyFilename Certificate key filename + ## + certKeyFilename: "" + ## @param tls.certCAFilename CA Certificate filename + ## + certCAFilename: "" + + secretName: ~ + existingSecret: "" + +gateway: + enabled: false + dedicated: false + gatewayApi: false + name: "" + namespace: "" + gatewayClassName: istio + ## @param gateway.listeners + ## + listeners: [] + existingGateway: ~ + existingVirtualService: ~ + ## @param gateway.extraRoute Array of extra Kubernetes Gateway API Route to deploy with the release + ## + extraRoute: [] + +## Prometheus exporter configuration +## +metrics: + ## @param metrics.enabled Start a side-car prometheus exporter + ## + enabled: false + ## Bitnami FreeRADIUS Prometheus exporter image + ## ref: + ## @param metrics.image.registry FreeRADIUS Prometheus exporter image registry + ## @param metrics.image.repository FreeRADIUS Prometheus exporter image repository + ## @param metrics.image.tag FreeRADIUS Prometheus exporter image tag (immutable tags are recommended) + ## @param metrics.image.pullPolicy FreeRADIUS Prometheus exporter image pull policy + ## @param metrics.image.pullSecrets FreeRADIUS Prometheus exporter image pull secrets + ## + image: + registry: docker.io + repository: + tag: + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets (secrets must be manually created in the namespace) + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + + ## Prometheus Operator PrometheusRule configuration + ## + prometheusRules: + ## @param metrics.prometheusRules.enabled if `true`, creates a Prometheus Operator PrometheusRule (also requires `metrics.enabled` to be `true`, and makes little sense without ServiceMonitor) + ## + enabled: false + ## @param metrics.prometheusRules.additionalLabels [object] Additional labels to add to the PrometheusRule so it is picked up by the operator + ## If using the [Helm Chart](https://github.com/helm/charts/tree/master/stable/prometheus-operator) this is the name of the Helm release and 'app: prometheus-operator' + ## + additionalLabels: + app: prometheus-operator + release: prometheus + ## @param metrics.prometheusRules.rules PrometheusRule rules to configure + ## e.g: + ## - alert: FreeRADIUS-Down + ## annotations: + ## message: 'FreeRADIUS instance {{ $labels.instance }} is down' + ## summary: FreeRADIUS instance is down + ## expr: absent(up{job="freeradius"} == 1) + ## labels: + ## severity: warning + ## service: freeradius + ## for: 5m + ## + rules: {}