{"id":20365842,"url":"https://github.com/cycoresystems/asterisk-config","last_synced_at":"2025-04-12T04:50:50.376Z","repository":{"id":34395080,"uuid":"138233154","full_name":"CyCoreSystems/asterisk-config","owner":"CyCoreSystems","description":"Kubernetes dynamic configuration engine for Asterisk","archived":false,"fork":false,"pushed_at":"2022-06-17T15:20:32.000Z","size":106,"stargazers_count":66,"open_issues_count":3,"forks_count":26,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-08T14:07:24.734Z","etag":null,"topics":["asterisk","go","golang","kubernetes"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CyCoreSystems.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-21T23:48:10.000Z","updated_at":"2025-03-20T12:32:51.000Z","dependencies_parsed_at":"2022-08-11T22:00:37.034Z","dependency_job_id":null,"html_url":"https://github.com/CyCoreSystems/asterisk-config","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyCoreSystems%2Fasterisk-config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyCoreSystems%2Fasterisk-config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyCoreSystems%2Fasterisk-config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyCoreSystems%2Fasterisk-config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CyCoreSystems","download_url":"https://codeload.github.com/CyCoreSystems/asterisk-config/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248519473,"owners_count":21117757,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asterisk","go","golang","kubernetes"],"created_at":"2024-11-15T00:20:32.878Z","updated_at":"2025-04-12T04:50:50.350Z","avatar_url":"https://github.com/CyCoreSystems.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Asterisk Config\n\nAsterisk Config is a kubernetes sidecar container which constructs the\nconfiguration for Asterisk.  It is comprised of a custom configuration set and a\nstandardized dynamic environment set to build the Asterisk configuration for the\nPod in question.\n\nThe primary dynamic component of Asterisk Config is the IP address (internal and\nexternal) for use by the SIP and PJSIP modules.\n\n## Automatic reloading\n\nAny time dynamic data is updated, Asterisk is told to reload.  By default, we\nonly reload `res_pjsip.so`, since the dynamic data usually just involves PJSIP\nendpoint IPs.  However, you can set the `RELOAD_MODULES` environment variable to\na comma-separated list of modules which should be reloaded when the dynamic data\nis updated.\n\nThe reloads are performed by executing the ARI \"/asterisk/modules\" \"PUT\"\n(reload) once for each of the specified modules.  This ARI connection is\nautomatically created with a randomly-generated password by Asterisk Config.\n\n## Layering\n\nThere are two layers of files which are used:\n\n  - Default configuration\n  - Custom configuration\n\n### Default configuration\n\nIncluded within this package is the standard Asterisk basic configuration set\nwith minimal alterations to:\n\n  - include custom configurations\n  - include configuration directories\n  - disable all file-based logging\n\nAny file in the default configuration my be replaced by including it in your\ncustom configuration bundle, but see the Custom configuration section below for\nbetter methods.\n\nThe default configuration also creates configurations for ARI, so that it may\ncall a reload when necessary, and PJSIP, to configure the IP information for\ntransports.\n\n#### PJSIP default transports\n\nThe following default PJSIP transports will be specified:  \n\n  - `k8s-internal-ipv4-internal-media` (internal SIP/signaling advertisement,\n    internal RTP/media advertisement, port 5080/UDP)\n  - `k8s-internal-ipv4-external-media` (internal SIP/signaling advertisement,\n    external RTP/media advertisement, port 5070/UDP)\n  - `k8s-external-ipv4-external-media` (external SIP/signaling advertisement,\n    external RTP/media advertisement, port 5060/UDP)\n\nIn most cloud-based kubernetes setups, the Pod will be assigned an internal IP\naddress, and it will have a NATed external IP address.  The choice of transports\ndepends on two things:\n\n  - Where is the _signaling_ endpoint?\n  - Where is the _media_ endpoint?\n\nIt is common, for instance, to use kamailio as a SIP proxy to handle a scalable\nset of Asterisk servers.   In this case, you would want to use _internal_\nsignaling IPs.  The RTP, however, will depend on whether you want your media to\nflow _directly_ to your Asterisk Pods (`-external-media`) or by way of\n`rtpengine` or `rtpproxy` (`-internal-media`).\n\nFor each of your PJSIP `Endpoints`, just specify the transport you wish to\nuse.\n\n - ![Internal SIP, Internal RTP](./Documentation/pjsip-int-int.svg)\n - ![Internal SIP, External RTP](./Documentation/pjsip-int-ext.svg)\n - ![External SIP, External RTP](./Documentation/pjsip-ext-ext.svg)\n\n### Custom configuration\n\nWhile your custom configurations are allowed to overwrite any Asterisk\nconfiguration file, there are generally two schemes by which customized configurations may be\napplied:\n\n  - `\u003cmodule\u003e.d/XXXX.conf`\n  - `\u003cmodule\u003e_custom.conf`\n\nThe most flexible approach is to create any number of discrete files in the\nmodule configuration subdirectories.  For instance, you might add a PJSIP\nendpoint configuration in:\n\n`pjsip.d/ext-101.conf`\n\nAny file with the `.conf` extension in one of these directories will\nautomatically be loaded.\n\nModules which are configured to load configurations using this scheme are:\n\n  - AMI (`manager.d/`)\n  - ARI (`ari.d/`)\n  - Extensions (`extensions.d/`)\n  - PJSIP (`pjsip.d/`)\n  - Voicemail (`voicemail.d/`)\n\nIf there is any default configuration for any of these modules, that\nconfiguration will exist in `\u003cextension\u003e_custom.conf`.  The corresponding\n`\u003cextension\u003e.conf` only contains include statements.\n\nTake special note that ARI and PJSIP modules are used internally by Asterisk\nConfig, so changing their root `ari.conf` and `pjsip.conf` is not recommended\nunless you really know what you are doing.\n\n## Usage\n\nIt is presumed that you have a kubernetes installation on a standard cloud\nplatform (such as AWS, GCP, Azure, DigitalOcean, etc) or are running a baremetal\nkubernetes cluster which you can control to supply the public and private IP\naddresses for the Asterisk Pod.\n\nIt is strongly recommended to set the `CLOUD` environment variable to match your\nenvironment.  The valid options are:\n\n  - `aws` Amazon Web Services\n  - `azure` Microsoft Azure\n  - `digitalocean` or `do` Digital Ocean\n  - `gcp` Google Cloud Platform\n  - `` default discovery\n\nDefault discovery is useful for baremetal configurations or situations where you\ndo not wish to use the cloud provider's self discovery API. \n\n***NOTE***: Importantly, in cases where you need Asterisk to use the kubernetes\nPod IP address instead of the Node IP address, set the `CLOUD` variable to be\nthe empty string.  Default discovery also works for public IP addresses by using\nthe `jsonip.io` service.\n\nAsterisk Config offers varying levels of configuration complexity, allowing you\nto easily just get your Asterisk system off the ground or to build a\nfully-templated configuration set.\n\nIt is a common problem that Asterisk may start before the config has been\nwritten.  In order to eliminate that eventuality, you should check for the\nexistence of the `.asterisk-config` file before allowing Asterisk to start.\n\n### Basic Usage\n\nThe simplest use is: to create the set of custom Asterisk configurations\n\n  1. create the set of custom Asterisk configurations for your scenario\n  2. generate a `.zip` file of that configuration tree\n  3. load that `.zip` file to a ConfigMap, Secret, or Web URL\n\nFor example:\n\nWe will define a simple dialplan with a single PJSIP endpoint to a carrier.\nWhen a call comes in from the carrier, it will be answered and any audio\nreceived will be played back to the caller.\n\nFirst, create a directory to contain the configuration files.  Files stored in\nthis directory will be copied into `/etc/asterisk/` on the live Asterisk Pod.\nIn this example, we will use the local directory named\n`/home/user/asterisk/config`.\n\nInside your directory, we create two files: `pjsip.d/my_carrier.conf` and\n`extensions.d/dialin.conf`.\n\n`pjsip.d/my_carrier.conf`:\n\n```ini\n[pstn]\ntype=endpoint\ntransport=k8s-external-ipv4-external-media\ncontext=dialin\ndisallow=all\nallow=ulaw\naors=pstn\nrtp_symmetric=yes\n\n[pstn]\ntype=aor\ncontact=sip:my.carrier.com:5060\n\n[pstn]\ntype=identify\nendpoint=pstn\nmatch=12.34.56.78\nmatch=87.65.43.21\n\n[acl]\ntype=acl\ndeny=0.0.0.0/0.0.0.0\npermit=12.34.56.78/255.255.255.255\npermit=87.65.43.21/255.255.255.255\n```\n\n`extensions.d/dialin.conf`:\n\n```ini\n[dialin]\nexten = echo,1,Verbose(1, \"Running Echo\")\n same = n,Answer()\n same = n,Echo()\n same = n,Hangup()\n\nexten = 15555555555,1,Verbose(1, \"Received call to +1 555 555.5555\")\n same = n,Goto(echo,1)\n```\n\nNow zip up these configuration files to a new `asterisk-config.zip`:\n\n```sh\nzip -r asterisk-config.zip *\n```\n\nThen store the `asterisk-config.zip` file to kubernetes as a Secret named\n\"asterisk-config\":\n\n```sh\nkubectl create secret generic asterisk-config --from-file=asterisk-config.zip\n```\n\n**NOTE**:  By default, Asterisk-Config looks for the Secret named\n\"asterisk-config\" to load the custom configuration.  See the section below for\nsourcing the custom configuration from a different location.\n\nNow we create a normal Pod spec for kubernetes including the Asterisk\nConfiguration sidecar container:\n\n```yaml\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  name: asterisk\n  labels:\n    component: asterisk\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        component: asterisk\n    spec:\n      hostNetwork: true\n      containers:\n        - name: config\n          image: ghcr.io/cycoresystems/asterisk-config\n          env:\n            - name: POD_NAMESPACE\n              valueFrom:\n                fieldRef:\n                  fieldPath: metadata.namespace\n          volumeMounts:\n            - name: config\n              mountPath: /etc/asterisk\n            - name: source\n              mountPath: /source\n        - name: asterisk\n          image: cycoresystems/asterisk\n          volumeMounts:\n            - name: config\n              mountPath: /etc/asterisk\n      volumes:\n        - name: config\n        - name: source\n          secret:\n            secretName: \"asterisk-config\"\n```\n\n\n## Custom Configuration source\n\nBy default, Asterisk Config looks for the file `/source/asterisk-config.zip` as\nthe source of configuration.  However, this can be customized by setting the\n`SOURCE` environment variable.\n\nYou may also obtain the source from an HTTP URL by specifying that URL as the\n`SOURCE`.  Additional environment variables may be provided for HTTP authentication:\n\n  - `URL_USERNAME` (for basic authentication)\n  - `URL_PASSWORD` (for basic authentication),\n  - `URL_AUTHORIZATION` (explicit `\"Authorization\" header`)\n\nIf no `SOURCE` file can be found or is specified, Asterisk Config will attempt to\nload the (expanded) configuration tree in the `/custom/` directory.  In this\nway, you may plug in your own source-obtaining method and have it populate the\ncustom configuration files in this directory.\n\nTo make sure the Asterisk container is not successfully started before the\nconfiguration can be loaded, Asterisk Config will die if no valid custom\nconfiguration can be obtained.  Asterisk will already die if it cannot find its\nconfiguration.  Kubernetes will automatically restart each of these if they die.\n\n## Templates\n\nAsterisk Config will process any file within the source bundle which ends in the\n`.tmpl` extension.  These files will be processed as Go `text/template`\nfiles and the output stored as the same filename without the `.tmpl` extension.\n\nValues for the templates may come from a number of sources:\n\n  - ConfigMap\n  - Environment Variables\n  - Service\n  - Endpoints (of a Service)\n  - EndpointIPs (of a Service)\n  - Network\n\n### ConfigMap\n\nTo obtain ConfigMap entries, Asterisk Config will use the Kubernetes API to\nattempt to pull in the ConfigMap and key requested. \n\n**Format**:  `{{.ConfigMap \"\u003cname\u003e\" \"\u003cnamespace\u003e\" \"\u003ckey\u003e\"}}` \n\nThe provided namespace _may_ be `\"\"` if both the ConfigMap is in the same\nnamespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly\nset.\n\nThe ConfigMap will be monitored by Asterisk Config, and if it is updated, the\nconfiguration files will be regenerated, and a reload will be performed.\n\nNote that this will likely require an RBAC entry to allow the `ServiceAccount`\nunder which Asterisk Config is running to access the referenced ConfigMap.\n\n\n### Environment Variables\n\n**Format**: `{{.Env \"\u003cname\u003e\"}}`\n\nIt is useful to note that IP addresses of services within the same namespace\nwill automatically be populated as environment variables by kubernetes.  These\nwill be of the form `\u003cSERVICE_NAME\u003e_SERVICE_HOST`.  For instance, the IP of a\nservice named \"kamailio\" will be stored in the environment variable\n`KAMAILIO_SERVICE_HOST`.  This is a normal, default feature of all kubernetes\ncontainers.  See the [documentation](https://kubernetes.io/docs/concepts/services-networking/service/) for more information.\n\n### Service\n\nData from a kubernetes Service may be obtained using the Kubernetes API.\n\n**Format**: `{{.Service \"\u003cname\u003e\" \"\u003cnamespace\u003e]\"}}`\n\nThe provided namespace _may_ be `\"\"` if both the Service is in the same\nnamespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly\nset.\n\nThe value returned here is the Kubernetes\n[Service](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#service-v1-core).\nKeep in mind that Go uses PascalCase for the fields, so \"clusterIP\" becomes\n\"ClusterIP\".\n\nFor example, to get the ClusterIP of a service named \"kamailio\" in the \"voip\"\nnamespace:\n\n`{{ with .Service \"kamailio\" \"voip\"}}{{.Spec.ClusterIP}}{{end}}`\n\nNote that the IP address of a service within the same namespace can be obtained\nmore simply by environment variable, as described above.\n\n\n### Endpoints\n\nData from the kubernetes Endpoints of a Service may be obtained using the\nKubernetes API.\n\n**Format**: `{{.Service \"\u003cname\u003e\" \"\u003cnamespace\u003e\"}}`\n\nThe provided namespace _may_ be `\"\"` if both the Service is in the same\nnamespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly\nset.\n\nThe value returned is the Kubernetes [Endpoints](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#endpoints-v1-core).\n\nThe Endpoints will be monitored by Asterisk Config, and if it is updated, the\nconfiguration files will be regenerated, and a reload will be performed.\n\nThis is usually used to obtain the dynamic set of proxy servers, but since the\nmost common reason to do this is to obtain the set of IPs for endpoints of a\nservice, we provide a second helper function just for that.\n\n### Endpoint IPs\n\nOne of the most common pieces of dynamic data to retrieve is the set of IPs for\nthe endpoints of a service.  Therefore, to simplify the relatively tedious\niteration of these directly from the Endpoints spec, we provide the EndpointIPs\nmacro, which returns the list of IPs of all Endpoints of the given service\nname.\n\n**Format**: `{{.EndpointIPs \"\u003cname\u003e\" \"\u003cnamespace\u003e\"}}`\n\nThe provided namespace _may_ be `\"\"` if both the Service is in the same\nnamespace as the Pod _and_ the `POD_NAMESPACE` environment variable is properly\nset.\n\nUsing this is then easy.  For example, to create a PJSIP endpoint from the set\nof proxy servers running as the \"kamailio\" service:\n\n`pjsip.d/proxies.conf`:\n\n```ini\n[proxies]\ntype=endpoint\ntransport=k8s-internal-ipv4-external-media\ncontext=from-proxies\ndisallow=all\nallow=ulaw\naors=proxies\nrtp_symmetric=yes\n\n[proxies]\ntype=aor\n{{range .EndpointIPs \"kamailio\"}}\ncontact=sip:{{.}}\n{{end}}\n\n[proxies]\ntype=identify\nendpoint=proxies\n{{range .EndpointIPs \"kamailio\"}}\nmatch={{.}}\n{{end}}\n\n[proxies]\ntype=acl\ndeny=0.0.0.0/0.0.0.0\n{{range .EndpointIPs \"kamailio\"}}\npermit={{.}}\n{{end}}\n```\n\nThe Endpoints IPs will be monitored by Asterisk Config, and if they are updated, the\nconfiguration files will be regenerated, and a reload will be performed.\n\n\n### Network data\n\nThe IP addresses for the running Pod are made available, as well.\n\n**Format**: `{{.Network \"\u003ckind\u003e\"}}`\n\nThe available data kinds correspond to the data available from\n[NetDiscover](https://github.com/CyCoreSystems/netdiscover):\n\n  - \"hostname\"\n  - \"privatev4\"\n  - \"publicv4\"\n  - \"publicv6\"\n\nNote that PJSIP transports are already automatically set up, as described above.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcycoresystems%2Fasterisk-config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcycoresystems%2Fasterisk-config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcycoresystems%2Fasterisk-config/lists"}