opensipscli 0.4.0__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- opensipscli-0.4.2/.github/workflows/docker-push-image.yml +38 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/.github/workflows/docker-readme.yml +2 -2
- {opensipscli-0.4.0 → opensipscli-0.4.2}/.github/workflows/pypi.yml +6 -6
- {opensipscli-0.4.0 → opensipscli-0.4.2}/PKG-INFO +3 -3
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docs/INSTALLATION.md +2 -2
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docs/modules/database.md +15 -1
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docs/modules/mi.md +6 -1
- opensipscli-0.4.2/docs/modules/tls.md +191 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/cli.py +10 -3
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/db.py +51 -42
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/modules/database.py +70 -1
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/modules/mi.py +29 -3
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/modules/tls.py +337 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/version.py +1 -1
- {opensipscli-0.4.0 → opensipscli-0.4.2}/packaging/debian/changelog +12 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/packaging/debian/control +1 -1
- {opensipscli-0.4.0 → opensipscli-0.4.2}/packaging/redhat_fedora/opensips-cli.spec +7 -3
- {opensipscli-0.4.0 → opensipscli-0.4.2}/pyproject.toml +1 -1
- {opensipscli-0.4.0 → opensipscli-0.4.2}/setup.py +1 -1
- {opensipscli-0.4.0 → opensipscli-0.4.2}/test/alltests.py +12 -0
- opensipscli-0.4.0/.github/workflows/docker-push-image.yml +0 -26
- opensipscli-0.4.0/docs/modules/tls.md +0 -99
- {opensipscli-0.4.0 → opensipscli-0.4.2}/.gitignore +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/LICENSE +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/README.md +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/SECURITY.md +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/bin/opensips-cli +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docker/Dockerfile +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docker/Makefile +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docker/docker.md +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docker/run.sh +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docs/modules/diagnose.md +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docs/modules/instance.md +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docs/modules/trace.md +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docs/modules/trap.md +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/docs/modules/user.md +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/etc/default.cfg +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/__init__.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/args.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/comm.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/config.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/defaults.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/libs/__init__.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/libs/sqlalchemy_utils.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/logger.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/main.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/module.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/modules/__init__.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/modules/diagnose.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/modules/instance.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/modules/trace.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/modules/trap.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/opensipscli/modules/user.py +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/packaging/debian/.gitignore +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/packaging/debian/compat +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/packaging/debian/copyright +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/packaging/debian/rules +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/packaging/debian/source/format +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/packaging/debian/watch +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/setup.cfg +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/test/test-database.sh +0 -0
- {opensipscli-0.4.0 → opensipscli-0.4.2}/test/test.sh +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Push OpenSIPS CLI Images in Docker Hub
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
repository_dispatch:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v6
|
|
14
|
+
|
|
15
|
+
- name: Set up Docker Buildx
|
|
16
|
+
uses: docker/setup-buildx-action@v4
|
|
17
|
+
|
|
18
|
+
- name: Log in to Docker Hub
|
|
19
|
+
uses: docker/login-action@v4
|
|
20
|
+
with:
|
|
21
|
+
username: ${{ secrets.DOCKER_USERNAME }}
|
|
22
|
+
password: ${{ secrets.DOCKER_TOKEN }}
|
|
23
|
+
|
|
24
|
+
- name: Log in to GitHub Container Registry
|
|
25
|
+
uses: docker/login-action@v4
|
|
26
|
+
with:
|
|
27
|
+
registry: ghcr.io
|
|
28
|
+
username: ${{ github.repository_owner }}
|
|
29
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
30
|
+
|
|
31
|
+
- name: Build and push Docker image
|
|
32
|
+
uses: docker/build-push-action@v7
|
|
33
|
+
with:
|
|
34
|
+
context: ./docker/
|
|
35
|
+
push: true
|
|
36
|
+
tags: |
|
|
37
|
+
opensips/opensips-cli:latest
|
|
38
|
+
ghcr.io/opensips/opensips-cli:latest
|
|
@@ -12,11 +12,11 @@ jobs:
|
|
|
12
12
|
dockerHubDescription:
|
|
13
13
|
runs-on: ubuntu-latest
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
- name: Docker Hub Description
|
|
19
|
-
uses: peter-evans/dockerhub-description@
|
|
19
|
+
uses: peter-evans/dockerhub-description@v5
|
|
20
20
|
with:
|
|
21
21
|
username: ${{ secrets.DOCKER_USERNAME }}
|
|
22
22
|
password: ${{ secrets.DOCKER_TOKEN }}
|
|
@@ -9,9 +9,9 @@ jobs:
|
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
10
|
|
|
11
11
|
steps:
|
|
12
|
-
- uses: actions/checkout@
|
|
12
|
+
- uses: actions/checkout@v6
|
|
13
13
|
- name: Set up Python
|
|
14
|
-
uses: actions/setup-python@
|
|
14
|
+
uses: actions/setup-python@v6
|
|
15
15
|
with:
|
|
16
16
|
python-version: "3.x"
|
|
17
17
|
- name: Install pypa/build
|
|
@@ -23,7 +23,7 @@ jobs:
|
|
|
23
23
|
- name: Build a binary wheel and a source tarball
|
|
24
24
|
run: python3 -m build
|
|
25
25
|
- name: Store the distribution packages
|
|
26
|
-
uses: actions/upload-artifact@
|
|
26
|
+
uses: actions/upload-artifact@v7
|
|
27
27
|
with:
|
|
28
28
|
name: python-package-distributions
|
|
29
29
|
path: dist/
|
|
@@ -43,7 +43,7 @@ jobs:
|
|
|
43
43
|
|
|
44
44
|
steps:
|
|
45
45
|
- name: Download all the dists
|
|
46
|
-
uses: actions/download-artifact@
|
|
46
|
+
uses: actions/download-artifact@v8
|
|
47
47
|
with:
|
|
48
48
|
name: python-package-distributions
|
|
49
49
|
path: dist/
|
|
@@ -64,12 +64,12 @@ jobs:
|
|
|
64
64
|
|
|
65
65
|
steps:
|
|
66
66
|
- name: Download all the dists
|
|
67
|
-
uses: actions/download-artifact@
|
|
67
|
+
uses: actions/download-artifact@v8
|
|
68
68
|
with:
|
|
69
69
|
name: python-package-distributions
|
|
70
70
|
path: dist/
|
|
71
71
|
- name: Sign the dists with Sigstore
|
|
72
|
-
uses: sigstore/gh-action-sigstore-python@
|
|
72
|
+
uses: sigstore/gh-action-sigstore-python@v3.5.0
|
|
73
73
|
with:
|
|
74
74
|
inputs: >-
|
|
75
75
|
./dist/*.tar.gz
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: opensipscli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: OpenSIPS Command Line Interface
|
|
5
5
|
Project-URL: Homepage, https://github.com/OpenSIPS/opensips-cli
|
|
6
6
|
Project-URL: Source, https://github.com/OpenSIPS/opensips-cli
|
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
16
16
|
Requires-Python: >=3.8
|
|
17
17
|
Requires-Dist: opensips
|
|
18
18
|
Requires-Dist: pymysql
|
|
19
|
-
Requires-Dist: sqlalchemy>=1.3.
|
|
19
|
+
Requires-Dist: sqlalchemy>=1.3.2
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
|
|
22
22
|
# OpenSIPS CLI (Command Line Interface)
|
|
@@ -17,8 +17,8 @@ to your system using the instructions provided, then install the
|
|
|
17
17
|
|
|
18
18
|
Supported Operating Systems (at the time of writing):
|
|
19
19
|
|
|
20
|
-
* Debian
|
|
21
|
-
* Ubuntu
|
|
20
|
+
* Debian 10-12
|
|
21
|
+
* Ubuntu 18.04, 20.04, 22.04, 24.04
|
|
22
22
|
|
|
23
23
|
### RPM packages (.rpm)
|
|
24
24
|
|
|
@@ -14,7 +14,10 @@ which database to delete.
|
|
|
14
14
|
parameter the name of the module, as specified in the OpenSIPS scripts
|
|
15
15
|
hierarchy.
|
|
16
16
|
* `migrate` - copy and convert an OpenSIPS database into its next OpenSIPS
|
|
17
|
-
release equivalent
|
|
17
|
+
release equivalent
|
|
18
|
+
* `pi` - creates a `pi_http` framework from the framework shipped with
|
|
19
|
+
OpenSIPS, using the configured database URL and modules. An optional output
|
|
20
|
+
path may be provided.
|
|
18
21
|
|
|
19
22
|
## Configuration
|
|
20
23
|
|
|
@@ -90,6 +93,17 @@ opensips-cli -x database add rtpproxy
|
|
|
90
93
|
```
|
|
91
94
|
The command above will create the `rtpproxy_sockets` table.
|
|
92
95
|
|
|
96
|
+
To create a provisioning framework for the configured modules, run:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
opensips-cli -x database pi /etc/opensips/pi_framework.xml
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The command reuses the framework shipped in the OpenSIPS `pi_http` scripts,
|
|
103
|
+
including its module-specific columns, validations, and commands. When
|
|
104
|
+
`database_modules` is not `ALL`, entries for other modules are removed from
|
|
105
|
+
the generated file.
|
|
106
|
+
|
|
93
107
|
A drop command will prompt the user whether they really want to drop the
|
|
94
108
|
database or not:
|
|
95
109
|
|
|
@@ -7,9 +7,14 @@ commands and display the result in the console.
|
|
|
7
7
|
|
|
8
8
|
This module exports all the commands that are exported by the OpenSIPS
|
|
9
9
|
instance that `opensips-cli` points to. It fetches the available commands by
|
|
10
|
-
running the OpenSIPS MI `which` command.
|
|
10
|
+
running the OpenSIPS MI `which` command. It also loads MI aliases using the
|
|
11
|
+
`which_aliases` command. When running a command, it returns
|
|
11
12
|
the raw, unprocessed data from OpenSIPS.
|
|
12
13
|
|
|
14
|
+
Aliases are accepted when executing commands, but are not included in command
|
|
15
|
+
completion suggestions. Ambiguous aliases are ignored and must be invoked by
|
|
16
|
+
their canonical command name.
|
|
17
|
+
|
|
13
18
|
Commands using this module can be run in two manners:
|
|
14
19
|
* using *positional* parameters: this is similar to the old way the
|
|
15
20
|
`opensipsctl` tool was working: the parameters passed to the function are
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# OpenSIPS CLI - TLS module
|
|
2
|
+
|
|
3
|
+
Using the `tls` module, you can generate TLS certificates and private keys.
|
|
4
|
+
|
|
5
|
+
The module has the following subcommands:
|
|
6
|
+
* `rootCA` - generates a CA (certification authority) self signed certificate
|
|
7
|
+
and private key pair. These are to be used by a TLS server.
|
|
8
|
+
* `userCERT` - generates a certificate signed by a given CA, a private key and
|
|
9
|
+
a CA list (chain of trust) file. These are to be used by TLS clients (users).
|
|
10
|
+
* `add` - adds a new TLS domain to the `tls_mgm` table.
|
|
11
|
+
* `update` - changes the columns of an existing TLS domain.
|
|
12
|
+
* `list` - lists the TLS domains provisioned in the `tls_mgm` table.
|
|
13
|
+
* `show` - prints the columns of a TLS domain.
|
|
14
|
+
* `delete` - removes a TLS domain from the `tls_mgm` table.
|
|
15
|
+
|
|
16
|
+
The `add`, `update`, `list`, `show` and `delete` subcommands provision the
|
|
17
|
+
`tls_mgm` module over the database, where the certificate, private key and CA
|
|
18
|
+
list are stored as BLOB values rather than as paths to files. A TLS domain is
|
|
19
|
+
identified by its name and its type (`server` or `client`), both passed as
|
|
20
|
+
arguments:
|
|
21
|
+
```
|
|
22
|
+
opensips-cli -x tls delete a.example.org server
|
|
23
|
+
```
|
|
24
|
+
The domain and its type may also be given by name, in which case they can
|
|
25
|
+
appear anywhere among the other columns:
|
|
26
|
+
```
|
|
27
|
+
opensips-cli -x tls delete domain=a.example.org type=server
|
|
28
|
+
```
|
|
29
|
+
Giving one of them both ways at once is an error. The commands addressing a
|
|
30
|
+
single domain ask for whatever is left out; `add` and `show` default the
|
|
31
|
+
type to `server`, while `update` and `delete` have no default and keep
|
|
32
|
+
asking until one is given, so that they cannot change a different domain than
|
|
33
|
+
the intended one.
|
|
34
|
+
|
|
35
|
+
`add` and `update` take the remaining `tls_mgm` columns as `column=value`
|
|
36
|
+
arguments, in any order and after the domain and the type:
|
|
37
|
+
```
|
|
38
|
+
opensips-cli -x tls add a.example.org server method=TLSv1_2 verify_cert=1
|
|
39
|
+
```
|
|
40
|
+
The settable columns are `match_ip_address`, `match_sip_domain`, `method`,
|
|
41
|
+
`verify_cert`, `require_cert`, `certificate`, `private_key`, `crl_check_all`,
|
|
42
|
+
`crl_dir`, `ca_list`, `ca_dir`, `cipher_list`, `dh_params` and `ec_curve`. A
|
|
43
|
+
column that is not given is left to its default in the database schema;
|
|
44
|
+
`update` only changes the columns it is given.
|
|
45
|
+
|
|
46
|
+
The `certificate`, `private_key`, `ca_list` and `dh_params` columns hold PEM
|
|
47
|
+
content, so their value is the path of the file holding it, and that file is
|
|
48
|
+
read and stored in the table:
|
|
49
|
+
```
|
|
50
|
+
opensips-cli -x tls add a.example.org server \
|
|
51
|
+
certificate=/etc/opensips/tls/user/user-cert.pem \
|
|
52
|
+
private_key=/etc/opensips/tls/user/user-privkey.pem
|
|
53
|
+
```
|
|
54
|
+
Every other column is stored as the value it is given, paths included: for
|
|
55
|
+
example, `ca_list` reads the file it points to, while `ca_dir` and `crl_dir`
|
|
56
|
+
keep the directory as such, which is what `tls_mgm` expects of them.
|
|
57
|
+
|
|
58
|
+
After every change, the `tls_reload` MI command is issued so that a running
|
|
59
|
+
OpenSIPS picks up the new domains. If OpenSIPS cannot be reached, a warning is
|
|
60
|
+
logged and the domains are loaded at the next restart.
|
|
61
|
+
|
|
62
|
+
## Configuration
|
|
63
|
+
|
|
64
|
+
Certificates and private keys can be customized using the following settings:
|
|
65
|
+
|
|
66
|
+
List of `opensips-cli.cfg` settings for configuring self-signed CA certificates:
|
|
67
|
+
|
|
68
|
+
* tls_ca_dir - output directory where the cert and key will be written to
|
|
69
|
+
* tls_ca_cert_file - output certificate file path, within `tls_ca_dir`
|
|
70
|
+
* tls_ca_key_file - output private key file path, within `tls_ca_dir`
|
|
71
|
+
* tls_ca_overwrite - set this to "y" in order to overwrite existing files
|
|
72
|
+
* tls_ca_common_name - the address of the website (e.g. "opensips.org")
|
|
73
|
+
* tls_ca_country - the initials of the country (e.g. "RO")
|
|
74
|
+
* tls_ca_state - the state (e.g. "Bucharest")
|
|
75
|
+
* tls_ca_locality - the city (e.g. "Bucharest")
|
|
76
|
+
* tls_ca_organisation - the name of the organisation (e.g. "OpenSIPS")
|
|
77
|
+
* tls_ca_organisational_unit - the organisational unit (e.g. "Project")
|
|
78
|
+
* tls_ca_notafter - the validity period, in seconds (e.g. 315360000)
|
|
79
|
+
* tls_ca_key_size - the size of the RSA key, in bits (e.g. 4096)
|
|
80
|
+
* tls_ca_md - the digest algorithm to use for signing (e.g. SHA256)
|
|
81
|
+
|
|
82
|
+
List of `opensips-cli.cfg` settings for configuring user certificates:
|
|
83
|
+
|
|
84
|
+
* tls_user_dir - output directory where the cert and key will be written to
|
|
85
|
+
* tls_user_cert_file - output certificate file path, within `tls_user_dir`
|
|
86
|
+
* tls_user_key_file - output private key file path, within `tls_user_dir`
|
|
87
|
+
* tls_user_calist_file - output CA list file path, within `tls_user_dir`
|
|
88
|
+
* tls_user_overwrite - set this to "y" in order to overwrite existing files
|
|
89
|
+
* tls_user_cacert - path to the input CA certificate
|
|
90
|
+
* tls_user_cakey - path to the input CA private key
|
|
91
|
+
* tls_user_common_name - the address of the website (e.g. "www.opensips.org")
|
|
92
|
+
* tls_user_country - the initials of the country (e.g. "RO")
|
|
93
|
+
* tls_user_state - the state (e.g. "Bucharest")
|
|
94
|
+
* tls_user_locality - the city (e.g. "Bucharest")
|
|
95
|
+
* tls_user_organisation - the name of the organisation (e.g. "OpenSIPS")
|
|
96
|
+
* tls_user_organisational_unit - the organisational unit (e.g. "Project")
|
|
97
|
+
* tls_user_notafter - the validity period, in seconds (e.g. 315360000)
|
|
98
|
+
* tls_user_key_size - the size of the RSA key, in bits (e.g. 4096)
|
|
99
|
+
* tls_user_md - the digest algorithm to use for signing (e.g. SHA256)
|
|
100
|
+
|
|
101
|
+
List of `opensips-cli.cfg` settings for the `tls_mgm` database subcommands:
|
|
102
|
+
|
|
103
|
+
* database_tls_url - URL of the database holding the `tls_mgm` table; falls
|
|
104
|
+
back to `database_url`
|
|
105
|
+
* database_tls_name - name of the database; falls back to `database_name`
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
## Examples
|
|
109
|
+
|
|
110
|
+
To create a self-signed certificate and a private key for rootCA, enter this snippet:
|
|
111
|
+
```
|
|
112
|
+
opensips-cli -x tls rootCA
|
|
113
|
+
```
|
|
114
|
+
Configuration file example for rootCA:
|
|
115
|
+
```
|
|
116
|
+
[default]
|
|
117
|
+
tls_ca_dir: /etc/opensips/tls/rootCA
|
|
118
|
+
tls_ca_cert_file: cacert.pem
|
|
119
|
+
tls_ca_key_file: private/cakey.pem
|
|
120
|
+
tls_ca_overwrite: yes
|
|
121
|
+
tls_ca_common_name: opensips.org
|
|
122
|
+
tls_ca_country: RO
|
|
123
|
+
tls_ca_state: Bucharest
|
|
124
|
+
tls_ca_locality: Bucharest
|
|
125
|
+
tls_ca_organisation: OpenSIPS
|
|
126
|
+
tls_ca_organisational_unit: Project
|
|
127
|
+
tls_ca_notafter: 315360000
|
|
128
|
+
tls_ca_key_size: 4096
|
|
129
|
+
tls_ca_md: SHA256
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
To create a user certificate signed by the above rootCA, along with a private
|
|
133
|
+
key and a CA list (chain of trust) file:
|
|
134
|
+
```
|
|
135
|
+
opensips-cli -x tls userCERT
|
|
136
|
+
```
|
|
137
|
+
Configuration file example for userCERT:
|
|
138
|
+
```
|
|
139
|
+
[default]
|
|
140
|
+
tls_user_dir: /etc/opensips/tls/user
|
|
141
|
+
tls_user_cert_file: user-cert.pem
|
|
142
|
+
tls_user_key_file: user-privkey.pem
|
|
143
|
+
tls_user_calist_file: user-calist.pem
|
|
144
|
+
tls_user_overwrite: yes
|
|
145
|
+
tls_user_cacert: /etc/opensips/tls/rootCA/cacert.pem
|
|
146
|
+
tls_user_cakey: /etc/opensips/tls/rootCA/private/cakey.pem
|
|
147
|
+
tls_user_common_name: www.opensips.org
|
|
148
|
+
tls_user_country: RO
|
|
149
|
+
tls_user_state: Bucharest
|
|
150
|
+
tls_user_locality: Bucharest
|
|
151
|
+
tls_user_organisation: OpenSIPS
|
|
152
|
+
tls_user_organisational_unit: Project
|
|
153
|
+
tls_user_notafter: 315360000
|
|
154
|
+
tls_user_key_size: 4096
|
|
155
|
+
tls_user_md: SHA256
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
To provision the certificate generated above as a TLS domain in the database:
|
|
159
|
+
```
|
|
160
|
+
opensips-cli -x tls add a.example.org server \
|
|
161
|
+
certificate=/etc/opensips/tls/user/user-cert.pem \
|
|
162
|
+
private_key=/etc/opensips/tls/user/user-privkey.pem \
|
|
163
|
+
ca_list=/etc/opensips/tls/user/user-calist.pem
|
|
164
|
+
```
|
|
165
|
+
Certificates issued by a public CA are provisioned the same way:
|
|
166
|
+
```
|
|
167
|
+
opensips-cli -x tls add a.example.org server \
|
|
168
|
+
certificate=/etc/letsencrypt/live/a.example.org/fullchain.pem \
|
|
169
|
+
private_key=/etc/letsencrypt/live/a.example.org/privkey.pem
|
|
170
|
+
```
|
|
171
|
+
Configuration file example for the `tls_mgm` database subcommands:
|
|
172
|
+
```
|
|
173
|
+
[default]
|
|
174
|
+
database_url: mysql://opensips:opensipsrw@localhost
|
|
175
|
+
database_name: opensips
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
To renew the certificate of a domain, or to change any of its other columns:
|
|
179
|
+
```
|
|
180
|
+
opensips-cli -x tls update a.example.org server \
|
|
181
|
+
certificate=/etc/letsencrypt/live/a.example.org/fullchain.pem \
|
|
182
|
+
private_key=/etc/letsencrypt/live/a.example.org/privkey.pem
|
|
183
|
+
opensips-cli -x tls update a.example.org server cipher_list=HIGH
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
To inspect and remove the provisioned domains:
|
|
187
|
+
```
|
|
188
|
+
opensips-cli -x tls list
|
|
189
|
+
opensips-cli -x tls show a.example.org server
|
|
190
|
+
opensips-cli -x tls delete a.example.org server
|
|
191
|
+
```
|
|
@@ -29,7 +29,6 @@ from opensipscli import comm
|
|
|
29
29
|
from opensipscli import defaults
|
|
30
30
|
from opensipscli.config import cfg
|
|
31
31
|
from opensipscli.logger import logger
|
|
32
|
-
from opensipscli.modules import *
|
|
33
32
|
|
|
34
33
|
class OpenSIPSCLI(cmd.Cmd, object):
|
|
35
34
|
"""
|
|
@@ -121,6 +120,10 @@ class OpenSIPSCLI(cmd.Cmd, object):
|
|
|
121
120
|
self.current_instance = instance
|
|
122
121
|
self.update_logger()
|
|
123
122
|
|
|
123
|
+
# import the modules only now, so that their import-time messages
|
|
124
|
+
# honor the logging level
|
|
125
|
+
importlib.import_module("opensipscli.modules")
|
|
126
|
+
|
|
124
127
|
# Update the intro and prompt
|
|
125
128
|
self.intro = cfg.get('prompt_intro')
|
|
126
129
|
self.prompt = '(%s): ' % cfg.get('prompt_name')
|
|
@@ -175,7 +178,11 @@ class OpenSIPSCLI(cmd.Cmd, object):
|
|
|
175
178
|
continue
|
|
176
179
|
logger.debug("Loaded module '{}'".format(name))
|
|
177
180
|
imod = mod()
|
|
178
|
-
|
|
181
|
+
methods = mod.__get_methods__(imod)
|
|
182
|
+
aliases = {}
|
|
183
|
+
if hasattr(imod, '__get_aliases__'):
|
|
184
|
+
aliases = imod.__get_aliases__() or {}
|
|
185
|
+
self.modules[name] = (imod, methods, aliases)
|
|
179
186
|
|
|
180
187
|
def history_write(self):
|
|
181
188
|
"""
|
|
@@ -419,7 +426,7 @@ class OpenSIPSCLI(cmd.Cmd, object):
|
|
|
419
426
|
logger.error("module '{}' expects the following commands: {}".
|
|
420
427
|
format(module, ", ".join(mod[1])))
|
|
421
428
|
return -1
|
|
422
|
-
elif cmd and not cmd in mod[
|
|
429
|
+
elif cmd and cmd not in mod[1] and cmd not in mod[2]:
|
|
423
430
|
logger.error("no command '{}' in module '{}'".
|
|
424
431
|
format(cmd, module))
|
|
425
432
|
return -1
|
|
@@ -36,17 +36,26 @@ try:
|
|
|
36
36
|
#from sqlalchemy.engine.url import make_url
|
|
37
37
|
|
|
38
38
|
sqlalchemy_available = True
|
|
39
|
+
sqlalchemy_import_error = None
|
|
39
40
|
logger.debug("SQLAlchemy version: %s", sqlalchemy.__version__)
|
|
40
41
|
# always use the vendored shim — the system sqlalchemy-utils package
|
|
41
42
|
# varies a lot across distros (0.36.x ships broken database_exists for
|
|
42
43
|
# PostgreSQL on Bullseye; 0.41.x is required for SA 2.0); the shim is
|
|
43
44
|
# tested against SA 1.3–2.0 and behaves consistently
|
|
44
45
|
from opensipscli.libs import sqlalchemy_utils
|
|
46
|
+
except ImportError as e:
|
|
47
|
+
# keep the cause around so callers can report it when the database
|
|
48
|
+
# is actually needed
|
|
49
|
+
logger.info("sqlalchemy not available: %s", e)
|
|
50
|
+
sqlalchemy_available = False
|
|
51
|
+
sqlalchemy_import_error = e
|
|
52
|
+
|
|
53
|
+
try:
|
|
45
54
|
import pymysql
|
|
46
55
|
pymysql.install_as_MySQLdb()
|
|
47
56
|
except ImportError:
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
# only needed for mysql:// URLs; the other backends work without it
|
|
58
|
+
pass
|
|
50
59
|
|
|
51
60
|
SUPPORTED_BACKENDS = [
|
|
52
61
|
"mysql",
|
|
@@ -210,7 +219,16 @@ class osdb(object):
|
|
|
210
219
|
|
|
211
220
|
# TODO: do this only for SQLAlchemy
|
|
212
221
|
try:
|
|
213
|
-
self.
|
|
222
|
+
if self.dialect == "sqlite":
|
|
223
|
+
# SQLite only got the AUTOCOMMIT isolation level in SA 1.3.16;
|
|
224
|
+
# older versions (EL8 ships 1.3.2) reject it with ArgumentError.
|
|
225
|
+
# Setting the pysqlite isolation_level to None gives the same
|
|
226
|
+
# autocommit behaviour on every supported SA version.
|
|
227
|
+
self.__engine = sqlalchemy.create_engine(
|
|
228
|
+
db_url, connect_args={'isolation_level': None})
|
|
229
|
+
else:
|
|
230
|
+
self.__engine = sqlalchemy.create_engine(
|
|
231
|
+
db_url, isolation_level='AUTOCOMMIT')
|
|
214
232
|
|
|
215
233
|
logger.debug("connecting to %s", db_url)
|
|
216
234
|
self.__conn = self.__engine.connect()
|
|
@@ -477,10 +495,10 @@ class osdb(object):
|
|
|
477
495
|
if not self.__conn:
|
|
478
496
|
raise osdbError("connection not available")
|
|
479
497
|
|
|
480
|
-
where_str = self.get_where(filter_keys)
|
|
498
|
+
where_str, params = self.get_where(filter_keys)
|
|
481
499
|
statement = "DELETE FROM {}{}".format(table, where_str)
|
|
482
500
|
try:
|
|
483
|
-
self.__conn.execute(text(statement))
|
|
501
|
+
self.__conn.execute(text(statement), params)
|
|
484
502
|
except sqlalchemy.exc.SQLAlchemyError as ex:
|
|
485
503
|
logger.error("cannot execute query: {}".format(statement))
|
|
486
504
|
logger.error(ex)
|
|
@@ -658,13 +676,13 @@ class osdb(object):
|
|
|
658
676
|
elif type(fields) != list:
|
|
659
677
|
fields = [ fields ]
|
|
660
678
|
|
|
661
|
-
where_str = self.get_where(filter_keys)
|
|
679
|
+
where_str, params = self.get_where(filter_keys)
|
|
662
680
|
statement = "SELECT {} FROM {}{}".format(
|
|
663
681
|
", ".join(fields),
|
|
664
682
|
table,
|
|
665
683
|
where_str)
|
|
666
684
|
try:
|
|
667
|
-
result = self.__conn.execute(text(statement))
|
|
685
|
+
result = self.__conn.execute(text(statement), params)
|
|
668
686
|
except sqlalchemy.exc.SQLAlchemyError as ex:
|
|
669
687
|
logger.error("cannot execute query: {}".format(statement))
|
|
670
688
|
logger.error(ex)
|
|
@@ -679,22 +697,18 @@ class osdb(object):
|
|
|
679
697
|
|
|
680
698
|
def get_where(self, filter_keys):
|
|
681
699
|
"""
|
|
682
|
-
construct a sql 'where clause' from given filter keys
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
where_str = " WHERE " + where_str[5:]
|
|
695
|
-
else:
|
|
696
|
-
where_str = ""
|
|
697
|
-
return where_str
|
|
700
|
+
construct a sql 'where clause' from given filter keys, along with
|
|
701
|
+
the parameters to bind to it
|
|
702
|
+
"""
|
|
703
|
+
if not filter_keys:
|
|
704
|
+
return "", {}
|
|
705
|
+
|
|
706
|
+
where_str = ""
|
|
707
|
+
params = {}
|
|
708
|
+
for i, (k, v) in enumerate(filter_keys.items()):
|
|
709
|
+
where_str += " AND {} = :w{}".format(k, i)
|
|
710
|
+
params["w{}".format(i)] = v
|
|
711
|
+
return " WHERE " + where_str[5:], params
|
|
698
712
|
|
|
699
713
|
def get_role(self, role_name="opensips"):
|
|
700
714
|
"""
|
|
@@ -762,6 +776,8 @@ class osdb(object):
|
|
|
762
776
|
check for support of a given database dialect via SQLAlchemy
|
|
763
777
|
"""
|
|
764
778
|
# TODO: do this only for SQLAlchemy
|
|
779
|
+
if not sqlalchemy_available:
|
|
780
|
+
return False
|
|
765
781
|
try:
|
|
766
782
|
sqlalchemy.create_engine('{}://'.format(dialect))
|
|
767
783
|
except sqlalchemy.exc.NoSuchModuleError:
|
|
@@ -781,18 +797,13 @@ class osdb(object):
|
|
|
781
797
|
if not self.__conn:
|
|
782
798
|
raise osdbError("connection not available")
|
|
783
799
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
values += ", "
|
|
787
|
-
if type(v) == int:
|
|
788
|
-
values += str(v)
|
|
789
|
-
else:
|
|
790
|
-
values += "'{}'".format(
|
|
791
|
-
v.translate(str.maketrans({'\'': '\\\''})))
|
|
800
|
+
cols = list(keys.keys())
|
|
801
|
+
params = {"v{}".format(i): keys[k] for i, k in enumerate(cols)}
|
|
792
802
|
statement = "INSERT INTO {} ({}) VALUES ({})".format(
|
|
793
|
-
table, ", ".join(
|
|
803
|
+
table, ", ".join(cols),
|
|
804
|
+
", ".join(":v{}".format(i) for i in range(len(cols))))
|
|
794
805
|
try:
|
|
795
|
-
result = self.__conn.execute(text(statement))
|
|
806
|
+
result = self.__conn.execute(text(statement), params)
|
|
796
807
|
except sqlalchemy.exc.SQLAlchemyError as ex:
|
|
797
808
|
logger.error("cannot execute query: {}".format(statement))
|
|
798
809
|
logger.error(ex)
|
|
@@ -874,18 +885,16 @@ class osdb(object):
|
|
|
874
885
|
raise osdbError("connection not available")
|
|
875
886
|
|
|
876
887
|
update_str = ""
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
v.translate(str.maketrans({'\'': '\\\''})))
|
|
884
|
-
where_str = self.get_where(filter_keys)
|
|
888
|
+
params = {}
|
|
889
|
+
for i, (k, v) in enumerate(update_keys.items()):
|
|
890
|
+
update_str += ", {} = :s{}".format(k, i)
|
|
891
|
+
params["s{}".format(i)] = v
|
|
892
|
+
where_str, where_params = self.get_where(filter_keys)
|
|
893
|
+
params.update(where_params)
|
|
885
894
|
statement = "UPDATE {} SET {}{}".format(table,
|
|
886
895
|
update_str[2:], where_str)
|
|
887
896
|
try:
|
|
888
|
-
result = self.__conn.execute(text(statement))
|
|
897
|
+
result = self.__conn.execute(text(statement), params)
|
|
889
898
|
except sqlalchemy.exc.SQLAlchemyError as ex:
|
|
890
899
|
logger.error("cannot execute query: {}".format(statement))
|
|
891
900
|
logger.error(ex)
|