2025年9月6日 星期六

privacyIDEA 3.11.4 Installation Notes

privacyIDEA 3.11.4  安裝筆記

所需軟體的 github URL

主程式

https://github.com/privacyidea/privacyidea

可以用 curl 或 wget 去下截 程式放在 /opt/privacyidea 即可

privacyidea-3.11.4.tar.gz 

或用 git  程式放在 /opt/privacyidea 即可 

git clone https://github.com/privacyidea/privacyidea.git

以下安裝是以 privacyidea-3.11.4 這個版本做記錄的


Windows 登入驗證  (TOTP 2FA)

https://github.com/privacyidea/privacyidea-credential-provider

privacyIDEACredentialProviderSetup-v3.7.0.3.msi

這個是裝在 windows server 2022 上面


本 LAB 的運作邏輯為 privacyIDEA ( server ) --> LDAP --> Windows AD 取得 2FA 使用對象的帳號,並建立 2FA Token (TOTP)


PC --> RDP --> 已加入網域 的 Windows server (已安裝 CredentialProvider)--> 輸入 正確的 ID + PWD + 2FA Token [雙因驗證達成]



Linux --> Oracle Linux 9 + Apache + WSGI + Mariadb + Python 3.12 + privacyidea-3.11.4    


安裝筆記開始....


vi /etc/yum.repos.d/oracle-linux-ol9.repo


[ol9_codeready_builder]

name=Oracle Linux 9 CodeReady Builder ($basearch) - (Unsupported)

baseurl=https://yum$ociregion.$ocidomain/repo/OracleLinux/OL9/codeready/builder/$basearch/

gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle

gpgcheck=1

enabled=1


dnf install oracle-epel-release-el9.x86_64

dnf install python3.12-*

dnf install git openssl-devel swig openldap-devel libsodium gcc

dnf install mariadb-server mariadb httpd httpd-devel mod_ssl



alternatives --install /usr/bin/python python3 /usr/bin/python3.12 1

alternatives --install /usr/bin/python python3 /usr/bin/python3.9 2

alternatives --config python3


There are 2 programs which provide 'python3'.


  Selection    Command

-----------------------------------------------

   1           /usr/bin/python3.12

*+ 2           /usr/bin/python3.9


Enter to keep the current selection[+], or type selection number: 1

[root@OL96 ]# python -V

Python 3.12.9


 python -m ensurepip --upgrade


ln -s /usr/bin/pip3.12 /usr/bin/pip

ln -s /usr/bin/pip3.12 /usr/bin/pip3


pip3 install -U pip setuptools

pip3 install virtualenv

pip3 install  pyOpenSSL

pip3 install mysql-connector-python


useradd -r -m privacyidea -d /opt/privacyidea

usermod -aG privacyidea apache


mysql 


CREATE DATABASE pi_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

CREATE USER 'pi_user'@'localhost' IDENTIFIED BY 'password';

GRANT ALL PRIVILEGES ON pi_db.* TO 'pi_user'@'localhost';

exit




vi /etc/profile.d/privacyidea.sh



export PRIVACYIDEA_HOME=/opt/privacyidea

export PATH=${PRIVACYIDEA_HOME}/bin:$PATH

export PRIVACYIDEA_CONFIGFILE=/etc/privacyidea/pi.cfg


source /etc/profile



mkdir -p /var/log/privacyidea

chmod 777 -R /var/log/privacyidea


virtualenv /opt/privacyidea

source /opt/privacyidea/bin/activate


cd /opt/privacyidea

pip3 install -r requirements.txt

pip3 install privacyidea==3.11.4


(privacyidea) [privacyidea@OL96 ~]#  pip3 install mod_wsgi


==> /opt/privacyidea/lib64/python3.12/site-packages/mod_wsgi/server/mod_wsgi-py312.cpython-312-x86_64-linux-gnu.so




pi-manage create_enckey

pi-manage create_audit_keys

pi-manage createdb

pi-manage admin add admin





[root@OL96 bin]# pi-manage create_enckey


             _                    _______  _______

   ___  ____(_)  _____ _______ __/  _/ _ \/ __/ _ |

  / _ \/ __/ / |/ / _ `/ __/ // // // // / _// __ |

 / .__/_/ /_/|___/\_,_/\__/\_, /___/____/___/_/ |_|

/_/                       /___/

                                            v3.11.4

.....

.....

......



[root@OL96 bin]# pi-manage createdb


             _                    _______  _______

   ___  ____(_)  _____ _______ __/  _/ _ \/ __/ _ |

  / _ \/ __/ / |/ / _ `/ __/ // // // // / _// __ |

 / .__/_/ /_/|___/\_,_/\__/\_, /___/____/___/_/ |_|

/_/                       /___/

                                            v3.11.4


DeprecationWarning: The command 'createdb' is deprecated.

Using connect string <SQLAlchemy mysql+pymysql://pi_user:password@localhost/pi_db......                                                                                                                                                             b?charset=utf8mb4>

Running online


[root@OL96 bin]# mysql

Welcome to the MariaDB monitor.  Commands end with ; or \g.

Your MariaDB connection id is 8

Server version: 10.5.27-MariaDB MariaDB Server


Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.


Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.



MariaDB [(none)]> show databases;

+--------------------+

| Database           |

+--------------------+

| information_schema |

| mysql              |

| performance_schema |

| pi_db              |

+--------------------+

....


MariaDB [(none)]> use pi_db;

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A


Database changed


MariaDB [pi_db]> show tables;

+-------------------------+

| Tables_in_pi_db         |

+-------------------------+

| admin                   |

| alembic_version         |

| audit_seq               |

| authcache               |

| authcache_seq           |

| caconfig_seq            |

| caconnector             |

| caconnector_seq         |

| caconnectorconfig       |

| challenge               |

| challenge_seq           |

| clientapp_seq           |

| clientapplication       |

......

.....

....


MariaDB [pi_db]> exit


[root@OL96 bin]# pi-manage admin add admin


             _                    _______  _______

   ___  ____(_)  _____ _______ __/  _/ _ \/ __/ _ |

  / _ \/ __/ / |/ / _ `/ __/ // // // // / _// __ |

 / .__/_/ /_/|___/\_,_/\__/\_, /___/____/___/_/ |_|

/_/                       /___/

                                            v3.11.4


Password:

Repeat for confirmation:

Admin admin was registered successfully.

[root@OL96 bin]#



[root@OL96 ~]# cat /etc/privacyidea/pi.cfg

import logging

# The realm, where users are allowed to login as administrators

SUPERUSER_REALM = ['super', 'administrators']

# Your database

SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://pi_user:password@localhost/pi_db'

# This is used to encrypt the auth_token

# This is used to encrypt the admin passwords

# This is used to encrypt the token data and token passwords

PI_ENCFILE = '/etc/privacyidea/enckey'

# This is used to sign the audit log

PI_AUDIT_KEY_PRIVATE = '/etc/privacyidea/private.pem'

PI_AUDIT_KEY_PUBLIC = '/etc/privacyidea/public.pem'

PI_AUDIT_SQL_TRUNCATE = True

# The Class for managing the SQL connection pool

PI_ENGINE_REGISTRY_CLASS = "shared"

PI_AUDIT_POOL_SIZE = 20

#PI_LOGFILE = '/tmp/privacyidea.log'

PI_LOGFILE = '/var/log/privacyidea/privacyidea.log'

PI_LOGLEVEL = logging.INFO

PI_PEPPER = 'v9EW6gt1SGEHgpBQpznTmPtn'

SECRET_KEY = 'BnLflBoiKfc9HOJyFR2agAv9'



[root@OL96 ~]# cat /etc/privacyidea/privacyideaapp.wsgi

import sys

sys.stdout = sys.stderr

from privacyidea.app import create_app

application = create_app(config_name="production", config_file="/etc/privacyidea                                                                                                                                                             /pi.cfg")

[root@OL96 ~]#


[root@OL96 privacyidea]# pwd

/etc/privacyidea

[root@OL96 privacyidea]# ll

total 20

-rwxr-xr-x 1 privacyidea apache   96 Sep  6 10:51 enckey

-rwxr-xr-x 1 privacyidea apache  881 Sep  6 10:49 pi.cfg

-rwxr-xr-x 1 privacyidea apache  164 Sep  6 10:48 privacyideaapp.wsgi

-rw-r--r-- 1 privacyidea apache 1679 Sep  6 10:50 private.pem

-rw-r--r-- 1 privacyidea apache  451 Sep  6 10:50 public.pem

[root@OL96 privacyidea]#


[root@OL96 privacyidea]# pwd

/opt/privacyidea

[root@OL96 privacyidea]# ll

total 116

drwxr-xr-x 5 privacyidea privacyidea    82 Jul  2 19:56 authmodules

-rwxr-xr-x 1 privacyidea privacyidea  9101 Jul  2 19:56 AUTHORS.md

drwxr-xr-x 3 privacyidea privacyidea  4096 Sep  6 10:44 bin

-rwxr-xr-x 1 privacyidea privacyidea   194 Sep  6 10:24 CACHEDIR.TAG

drwxr-xr-x 9 privacyidea privacyidea   188 Jul  2 19:56 deploy

drwxr-xr-x 3 privacyidea privacyidea    25 Sep  6 10:28 etc

drwxr-xr-x 3 privacyidea privacyidea    18 Sep  6 10:28 include

drwxr-xr-x 4 privacyidea privacyidea    43 Sep  6 10:28 lib

drwxr-xr-x 3 privacyidea privacyidea    24 Sep  6 10:24 lib64

-rwxr-xr-x 1 privacyidea privacyidea 32387 Jul  2 19:56 LICENSE

-rwxr-xr-x 1 privacyidea privacyidea   352 Jul  2 19:56 MANIFEST.in

drwxr-xr-x 3 privacyidea privacyidea    91 Jul  2 19:56 migrations

-rwxr-xr-x 1 privacyidea privacyidea 11480 Jul  2 19:56 PKG-INFO

drwxr-xr-x 8 privacyidea privacyidea   190 Jul  2 19:56 privacyidea

drwxr-xr-x 2 privacyidea privacyidea   154 Jul  2 19:56 privacyIDEA.egg-info

-rwxr-xr-x 1 privacyidea privacyidea   210 Sep  6 10:24 pyvenv.cfg

-rwxr-xr-x 1 privacyidea privacyidea  8603 Jul  2 19:56 README.rst

-rwxr-xr-x 1 privacyidea privacyidea  3646 Jul  2 19:56 requirements.txt

-rwxr-xr-x 1 privacyidea privacyidea    38 Jul  2 19:56 setup.cfg

-rwxr-xr-x 1 privacyidea privacyidea  5296 Jul  2 19:56 setup.py

drwxr-xr-x 3 privacyidea privacyidea    17 Sep  6 10:28 share

drwxr-xr-x 4 privacyidea privacyidea  8192 Jul  2 19:56 tests

drwxr-xr-x 2 privacyidea privacyidea  4096 Jul  2 19:56 tools

[root@OL96 privacyidea]#


[root@OL96 bin]# pwd

/opt/privacyidea/bin

[root@OL96 bin]# ll

total 304

-rwxr-xr-x 1 privacyidea privacyidea  2901 Sep  6 10:24 activate

-rwxr-xr-x 1 privacyidea privacyidea  2056 Sep  6 10:24 activate.csh

-rwxr-xr-x 1 privacyidea privacyidea  3744 Sep  6 10:24 activate.fish

-rwxr-xr-x 1 privacyidea privacyidea  2837 Sep  6 10:24 activate.nu

-rwxr-xr-x 1 privacyidea privacyidea  2657 Sep  6 10:24 activate.ps1

-rwxr-xr-x 1 privacyidea privacyidea  1321 Sep  6 10:24 activate_this.py

-rwxr-xr-x 1 privacyidea privacyidea   197 Sep  6 10:40 alembic

-rwxr-xr-x 1 privacyidea privacyidea   193 Sep  6 10:40 cbor2

-rwxr-xr-x 1 privacyidea privacyidea   750 Sep  6 10:28 creategoogleauthenticator-file

-rwxr-xr-x 1 privacyidea privacyidea   192 Sep  6 10:40 flask

-rwxr-xr-x 1 privacyidea privacyidea  1458 Sep  6 10:28 getgooglecodes

-rwxr-xr-x 1 privacyidea privacyidea   223 Sep  6 10:40 huey_consumer

-rwxr-xr-x 1 privacyidea privacyidea  1757 Sep  6 10:40 huey_consumer.py

-rwxr-xr-x 1 privacyidea privacyidea   197 Sep  6 10:40 mako-render

-rwxr-xr-x 1 privacyidea privacyidea   198 Sep  6 10:33 mod_wsgi-express

-rwxr-xr-x 1 privacyidea privacyidea   194 Sep  6 10:28 netaddr

-rwxr-xr-x 1 privacyidea privacyidea   217 Sep  6 10:40 normalizer

-rwxr-xr-x 1 privacyidea privacyidea   205 Sep  6 10:28 pi-manage

-rwxr-xr-x 1 privacyidea privacyidea   236 Sep  6 10:24 pip

-rwxr-xr-x 1 privacyidea privacyidea   236 Sep  6 10:24 pip3

-rwxr-xr-x 1 privacyidea privacyidea   236 Sep  6 10:24 pip-3.12

-rwxr-xr-x 1 privacyidea privacyidea   236 Sep  6 10:24 pip3.12

-rwxr-xr-x 1 privacyidea privacyidea   211 Sep  6 10:28 pi-tokenjanitor

-rwxr-xr-x 1 privacyidea privacyidea  2566 Sep  6 10:28 privacyidea-authorizedkeys

-rwxr-xr-x 1 privacyidea privacyidea  1748 Sep  6 10:28 privacyidea-convert-base32.py

-rwxr-xr-x 1 privacyidea privacyidea  2876 Sep  6 10:28 privacyidea-convert-token

-rwxr-xr-x 1 privacyidea privacyidea  3230 Sep  6 10:28 privacyidea-convert-xml-to-csv

-rwxr-xr-x 1 privacyidea privacyidea  2422 Sep  6 10:28 privacyidea-create-ad-users

-rwxr-xr-x 1 privacyidea privacyidea  1934 Sep  6 10:28 privacyidea-create-certificate

-rwxr-xr-x 1 privacyidea privacyidea  1907 Sep  6 10:28 privacyidea-create-pwidresolver-user

-rwxr-xr-x 1 privacyidea privacyidea  1529 Sep  6 10:28 privacyidea-create-sqlidresolver-user

-rwxr-xr-x 1 privacyidea privacyidea   914 Sep  6 10:28 privacyidea-create-userdb

-rwxr-xr-x 1 privacyidea privacyidea   207 Sep  6 10:28 privacyidea-cron

-rwxr-xr-x 1 privacyidea privacyidea  8408 Sep  6 10:28 privacyidea-diag

-rwxr-xr-x 1 privacyidea privacyidea   232 Sep  6 10:28 privacyidea-expired-users

-rwxr-xr-x 1 privacyidea privacyidea  4511 Sep  6 10:28 privacyidea-export-linotp-counter.py

-rwxr-xr-x 1 privacyidea privacyidea  1353 Sep  6 10:28 privacyidea-export-privacyidea-counter.py

-rwxr-xr-x 1 privacyidea privacyidea  3735 Sep  6 10:28 privacyidea-fetchssh

-rwxr-xr-x 1 privacyidea privacyidea  2453 Sep  6 10:28 privacyidea-fix-access-rights

-rwxr-xr-x 1 privacyidea privacyidea   227 Sep  6 10:28 privacyidea-get-serial

-rwxr-xr-x 1 privacyidea privacyidea   220 Sep  6 10:28 privacyidea-get-unused-tokens

-rwxr-xr-x 1 privacyidea privacyidea   302 Sep  6 10:46 privacyidea.log

-rwxr-xr-x 1 privacyidea privacyidea 25697 Sep  6 10:28 privacyidea-migrate-linotp.py

-rwxr-xr-x 1 privacyidea privacyidea  2539 Sep  6 10:28 privacyidea-pip-update

-rwxr-xr-x 1 privacyidea privacyidea  5793 Sep  6 10:28 privacyidea-queue-huey

-rwxr-xr-x 1 privacyidea privacyidea   631 Sep  6 10:28 privacyidea-schema-upgrade

-rwxr-xr-x 1 privacyidea privacyidea   213 Sep  6 10:28 privacyidea-standalone

-rwxr-xr-x 1 privacyidea privacyidea  8134 Sep  6 10:28 privacyidea-sync-owncloud.py

-rwxr-xr-x 1 privacyidea privacyidea   220 Sep  6 10:28 privacyidea-token-janitor

-rwxr-xr-x 1 privacyidea privacyidea  3816 Sep  6 10:28 privacyidea-update-counter.py

-rwxr-xr-x 1 privacyidea privacyidea  5420 Sep  6 10:28 privacyidea-update-linotp-counter.py

-rwxr-xr-x 1 privacyidea privacyidea  5473 Sep  6 10:28 privacyidea-user-action

-rwxr-xr-x 1 privacyidea privacyidea   236 Sep  6 10:28 privacyidea-usercache-cleanup

-rwxr-xr-x 1 privacyidea privacyidea   206 Sep  6 10:40 pybabel

drwxr-xr-x 2 privacyidea privacyidea  4096 Sep  6 10:40 __pycache__

-rwxr-xr-x 1 privacyidea privacyidea   196 Sep  6 10:40 pyrsa-decrypt

-rwxr-xr-x 1 privacyidea privacyidea   196 Sep  6 10:40 pyrsa-encrypt

-rwxr-xr-x 1 privacyidea privacyidea   194 Sep  6 10:40 pyrsa-keygen

-rwxr-xr-x 1 privacyidea privacyidea   217 Sep  6 10:40 pyrsa-priv2pub

-rwxr-xr-x 1 privacyidea privacyidea   190 Sep  6 10:40 pyrsa-sign

-rwxr-xr-x 1 privacyidea privacyidea   194 Sep  6 10:40 pyrsa-verify

lrwxrwxrwx 1 privacyidea privacyidea    19 Sep  6 10:24 python -> /usr/bin/python3.12

lrwxrwxrwx 1 privacyidea privacyidea     6 Sep  6 10:24 python3 -> python

lrwxrwxrwx 1 privacyidea privacyidea     6 Sep  6 10:24 python3.12 -> python

-rwxr-xr-x 1 privacyidea privacyidea  3133 Sep  6 10:28 reset-privacyidea

-rwxr-xr-x 1 privacyidea privacyidea   192 Sep  6 10:40 segno

[root@OL96 bin]#


[root@OL96 conf.d]# pwd

/etc/httpd/conf.d

[root@OL96 conf.d]# ll

total 36

-rw-r--r-- 1 root root 2916 Sep  2 16:02 autoindex.conf.bak

-rwxr-xr-x 1 root root 4409 Sep  6 12:00 privacyidea.conf

-rw-r--r-- 1 root root  400 Sep  2 16:02 README

-rw-r--r-- 1 root root 8720 Sep  2 16:00 ssl.conf.bak

-rw-r--r-- 1 root root 1252 Sep  2 16:00 userdir.conf.bak

-rw-r--r-- 1 root root  653 Sep  2 16:00 welcome.conf.bak

[root@OL96 conf.d]#


===> privacyidea.conf 


可自行參考   # cat /opt/privacyidea/deploy/apache/sites-available/privacyidea.conf


SSL 憑證可以用系統的即可,就是用預設的 ssl.conf 內所設定的


SSLCertificateFile /etc/pki/tls/certs/localhost.crt

SSLCertificateKeyFile /etc/pki/tls/private/localhost.key



可以需求或環境抄改如下設定,最簡單的方式就可將以下文件 + ssl.conf 整併也可.. 


[root@OL96 sites-available]# cat /opt/privacyidea/deploy/apache/sites-available/privacyidea.conf

<VirtualHost _default_:443>

        ServerAdmin webmaster@localhost

        # You might want to change this

        ServerName localhost


        DocumentRoot /var/www

        <Directory />

                # For Apache 2.4 you need to set this:

                Require all granted

                Options FollowSymLinks

                AllowOverride None

        </Directory>


        # Yubico servers use /wsapi/2.0/verify as the path in the

        # validation URL. Some tools (e.g. Kolab 2fa) let the

        # user/admin change the api host, but not the rest of

        # the URL. Uncomment the following two lines to reroute

        # the api URL internally to privacyideas /ttype/yubikey.

        #RewriteEngine  on

        #RewriteRule    "^/wsapi/2.0/verify"  "/ttype/yubikey" [PT]


        # We can run several instances on different paths with different configurations

        WSGIScriptAlias /      /etc/privacyidea/privacyideaapp.wsgi

        #WSGIScriptAlias /instance1      /home/cornelius/src/privacyidea/deploy/privacyideaapp1.wsgi

        #WSGIScriptAlias /instance2      /home/cornelius/src/privacyidea/deploy/privacyideaapp2.wsgi

        #WSGIScriptAlias /instance3      /home/cornelius/src/privacyidea/deploy/privacyideaapp3.wsgi

        #

        # The daemon is running as user 'privacyidea'

        # This user should have access to the encKey database encryption file

        WSGIDaemonProcess privacyidea processes=1 threads=15 display-name=%{GROUP} user=privacyidea

        WSGIProcessGroup privacyidea

        WSGIPassAuthorization On


        ErrorLog /var/log/apache2/error.log


        LogLevel warn

        # Do not use %q! This will reveal all parameters, including setting PINs and Keys!

        # Using SSL_CLINET_S_DN_CN will show you, which administrator did what task

        LogFormat "%h %l %u %t %>s \"%m %U %H\"  %b \"%{Referer}i\" \"%{User-agent}i\"" privacyIDEA

        CustomLog /var/log/apache2/ssl_access.log privacyIDEA


.....

....

....




優化 WSGI 


# cp /opt/privacyidea/lib64/python3.12/site-packages/mod_wsgi/server/mod_wsgi-py312.cpython-312-x86_64-linux-gnu.so /etc/httpd/modules/

# vi /etc/httpd/conf.modules.d/10-wsgi-python3.conf



[root@Oracle9]# cat /etc/httpd/conf.modules.d/10-wsgi-python3.conf 


# NOTE: mod_wsgi_python3 can not coexist in the same apache process as

# mod_wsgi (python2).  Only load if mod_wsgi is not already loaded.


<IfModule !wsgi_module>


    #LoadModule wsgi_module modules/mod_wsgi_python3.so


    LoadModule wsgi_module modules/mod_wsgi-py312.cpython-312-x86_64-linux-gnu.so


</IfModule>



#systemctl restart  httpd



優化成果


httpd log 

....

........ Apache/2.4.62 (Oracle Linux Server) OpenSSL/3.2.2 mod_wsgi/5.0.2 Python/3.12 configured -- resuming normal operations

....


其它參考資訊


==> privacyideaapp.wsgi


[root@OL96 apache]# cat /opt/privacyidea/deploy/apache/privacyideaapp.wsgi

import sys

sys.stdout = sys.stderr

from privacyidea.app import create_app

# Now we can select the config file:

application = create_app(config_name="production", config_file="/etc/privacyidea/pi.cfg")


==> pi.cfg


[root@OL96 deploy]# cat /opt/privacyidea/deploy/pi.cfg

import logging

# The realm, where users are allowed to login as administrators

SUPERUSER_REALM = ['super']

# Your database

SQLALCHEMY_DATABASE_URI = 'sqlite:////home/cornelius/src/privacyidea/data.sqlite'

# This is used to encrypt the auth_token

SECRET_KEY = 't0p s3cr3t'

# This is used to encrypt the admin passwords

PI_PEPPER = "Never know..."

# This is used to encrypt the token data and token passwords

PI_ENCFILE = '/home/cornelius/src/privacyidea/enckey'

# This is the dummy base class

#PI_AUDIT_MODULE = 'privacyidea.lib.auditmodules.base'

# This is the default

#PI_AUDIT_MODULE = 'privacyidea.lib.auditmodules.sqlaudit'

# This is used to sign the audit log

PI_AUDIT_KEY_PRIVATE = '/home/cornelius/src/privacyidea/private.pem'

PI_AUDIT_KEY_PUBLIC = '/home/cornelius/src/privacyidea/public.pem'

PI_AUDIT_SQL_TRUNCATE = True

# The Class for managing the SQL connection pool

PI_ENGINE_REGISTRY_CLASS = "shared"

PI_AUDIT_POOL_SIZE = 20


PI_LOGLEVEL = logging.INFO

# Extend the list of keys that will identify a machine to receive offline data

#OFFLINE_MACHINE_KEYS = ["myCustomKey", "myOtherKey"]

[root@OL96 deploy]#


Demo























沒有留言:

張貼留言