在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):fffonion/lua-resty-acme开源软件地址(OpenSource Url):https://github.com/fffonion/lua-resty-acme开源编程语言(OpenSource Language):Lua 55.9%开源软件介绍(OpenSource Introduction):lua-resty-acmeAutomatic Let's Encrypt certificate serving (RSA + ECC) and pure Lua implementation of the ACMEv2 protocol.
Table of ContentsDescriptionThis library consists of two parts:
Install using opm: opm install fffonion/lua-resty-acme Alternatively, to install using luarocks: luarocks install lua-resty-acme
# manually install a luafilesystem
luarocks install luafilesystem Note you will need to manually install This library uses an FFI-based openssl backend,
which currently supports OpenSSL StatusProduction. SynopsisCreate account private key and fallback certs: # create account key
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out /etc/openresty/account.key
# create fallback cert and key
openssl req -newkey rsa:2048 -nodes -keyout /etc/openresty/default.key -x509 -days 365 -out /etc/openresty/default.pem Use the following example config: events {}
http {
resolver 8.8.8.8 ipv6=off;
lua_shared_dict acme 16m;
# required to verify Let's Encrypt API
lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
lua_ssl_verify_depth 2;
init_by_lua_block {
require("resty.acme.autossl").init({
-- setting the following to true
-- implies that you read and accepted https://letsencrypt.org/repository/
tos_accepted = true,
-- uncomment following for first time setup
-- staging = true,
-- uncomment following to enable RSA + ECC double cert
-- domain_key_types = { 'rsa', 'ecc' },
-- uncomment following to enable tls-alpn-01 challenge
-- enabled_challenge_handlers = { 'http-01', 'tls-alpn-01' },
account_key_path = "/etc/openresty/account.key",
account_email = "[email protected]",
domain_whitelist = { "example.com" },
})
}
init_worker_by_lua_block {
require("resty.acme.autossl").init_worker()
}
server {
listen 80;
listen 443 ssl;
server_name example.com;
# fallback certs, make sure to create them before hand
ssl_certificate /etc/openresty/default.pem;
ssl_certificate_key /etc/openresty/default.key;
ssl_certificate_by_lua_block {
require("resty.acme.autossl").ssl_certificate()
}
location = /.well-known {
content_by_lua_block {
require("resty.acme.autossl").serve_http_challenge()
}
}
}
} When testing deployment, it's recommanded to uncomment the By default A certificate will be queued to create after Nginx seen request with such SNI, which might take tens of seconds to finish. During the meantime, requests with such SNI are responsed with the fallback certificate. Note that domain_whitelist = { "domain1.com", "domain2.com", "domain3.com" }, To match a pattern in your domain name, for example all subdomains under domain_whitelist_callback = function(domain, is_new_cert_needed)
return ngx.re.match(domain, [[\.example\.com$]], "jo")
end Furthermore, since checking domain whitelist is running in certificate phase. It's possible to use cosocket API here. Do note that this will increase the SSL handshake latency. domain_whitelist_callback = function(domain, is_new_cert_needed)
-- send HTTP request
local http = require("resty.http")
local res, err = httpc:request_uri("http://example.com")
-- access the storage
local value, err = require("resty.acme.autossl").storage:get("key")
-- do something to check the domain
-- return is_domain_included
end}),
In case of certificate request failure one may want to prevent ACME client to request another certificate immediatelly. By default, the cooloff period it is set to 300 seconds (5 minutes). It may be customized with failure_cooloff_callback = function(domain, count)
if count == 1 then
return 600 -- 10 minutes
elseif count == 2 then
return 1800 -- 30 minutes
elseif count == 3 then
return 3600 -- 1 hour
elseif count == 4 then
return 43200 -- 12 hours
elseif count == 5 then
return 43200 -- 12 hours
else
return 86400 -- 24 hours
end
end tls-alpn-01 challengetls-alpn-01 challenge is currently supported on Openresty Click to expand sample configevents {}
http {
resolver 8.8.8.8 ipv6=off;
lua_shared_dict acme 16m;
# required to verify Let's Encrypt API
lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
lua_ssl_verify_depth 2;
init_by_lua_block {
require("resty.acme.autossl").init({
-- setting the following to true
-- implies that you read and accepted https://letsencrypt.org/repository/
tos_accepted = true,
-- uncomment following for first time setup
-- staging = true,
-- uncomment folloing to enable RSA + ECC double cert
-- domain_key_types = { 'rsa', 'ecc' },
-- uncomment following to enable tls-alpn-01 challenge
enabled_challenge_handlers = { 'http-01', 'tls-alpn-01' },
account_key_path = "/etc/openresty/account.key",
account_email = "[email protected]",
domain_whitelist = { "example.com" },
storage_adapter = "file",
})
}
init_worker_by_lua_block {
require("resty.acme.autossl").init_worker()
}
server {
listen 80;
listen unix:/tmp/nginx-default.sock ssl;
# listen unix:/tmp/nginx-default.sock ssl proxy_protocol;
server_name example.com;
# set_real_ip_from unix:;
# real_ip_header proxy_protocol;
# fallback certs, make sure to create them before hand
ssl_certificate /etc/openresty/default.pem;
ssl_certificate_key /etc/openresty/default.key;
ssl_certificate_by_lua_block {
require("resty.acme.autossl").ssl_certificate()
}
location /.well-known {
content_by_lua_block {
require("resty.acme.autossl").serve_http_challenge()
}
}
}
}
stream {
init_worker_by_lua_block {
require("resty.acme.autossl").init({
-- setting the following to true
-- implies that you read and accepted https://letsencrypt.org/repository/
tos_accepted = true,
-- uncomment following for first time setup
-- staging = true,
-- uncomment folloing to enable RSA + ECC double cert
-- domain_key_types = { 'rsa', 'ecc' },
-- uncomment following to enable tls-alpn-01 challenge
enabled_challenge_handlers = { 'http-01', 'tls-alpn-01' },
account_key_path = "/etc/openresty/account.key",
account_email = "[email protected]",
domain_whitelist = { "example.com" },
storage_adapter = "file"
})
require("resty.acme.autossl").init_worker()
}
map $ssl_preread_alpn_protocols $backend {
~\bacme-tls/1\b unix:/tmp/nginx-tls-alpn.sock;
default unix:/tmp/nginx-default.sock;
}
server {
listen 443;
listen [::]:443;
ssl_preread on;
proxy_pass $backend;
# proxy_protocol on;
}
server {
listen unix:/tmp/nginx-tls-alpn.sock ssl;
# listen nix:/tmp/nginx-tls-alpn.sock ssl proxy_protocol;
ssl_certificate certs/default.pem;
ssl_certificate_key certs/default.key;
# requires --with-stream_realip_module
# set_real_ip_from unix:;
ssl_certificate_by_lua_block {
require("resty.acme.autossl").serve_tls_alpn_challenge()
}
content_by_lua_block {
ngx.exit(0)
}
}
} In the above sample config, we set a http server and two stream server. The very front stream server listens for 443 port and route to different upstream
based on client ALPN. The tls-alpn-01 responder listens on
resty.acme.autosslA config table can be passed to default_config = {
-- accept term of service https://letsencrypt.org/repository/
tos_accepted = false,
-- if using the let's encrypt staging API
staging = false,
-- the path to account private key in PEM format
account_key_path = nil,
-- the account email to register
account_email = nil,
-- number of certificate cache, per type
cache_size = 100,
domain_key_paths = {
-- the global domain RSA private key
rsa = nil,
-- the global domain ECC private key
ecc = nil,
},
-- the private key algorithm to use, can be one or both of
-- 'rsa' and 'ecc'
domain_key_types = { 'rsa' },
-- restrict registering new cert only with domain defined in this table
domain_whitelist = nil,
-- restrict registering new cert only with domain checked by this function
domain_whitelist_callback = nil,
-- interval to wait before retrying after failed certificate request
failure_cooloff = 300,
-- function that returns interval to wait before retrying after failed certificate request
failure_cooloff_callback = nil,
-- the threshold to renew a cert before it expires, in seconds
renew_threshold = 7 * 86400,
-- interval to check cert renewal, in seconds
renew_check_interval = 6 * 3600,
-- the store certificates
storage_adapter = "shm",
-- the storage config passed to storage adapter
storage_config = {
shm_name = 'acme',
},
-- the challenge types enabled
enabled_challenge_handlers = { 'http-01' },
-- time to wait before signaling ACME server to validate in seconds
challenge_start_delay = 0,
} If If Pass config table directly to ACME client as second parameter. The following example demonstrates how to use a CA provider other than Let's Encrypt and also set the preferred chain. resty.acme.autossl.init({
tos_accepted = true,
account_email = "[email protected]",
}, {
api_uri = "https://acme.otherca.com/directory",
preferred_chain = "OtherCA PKI Root CA",
}
) See also Storage Adapters below. When using distributed storage types, it's useful to bump up autossl.get_certkeysyntax: certkey, err = autossl.get_certkey(domain, type?) Return the PEM-encoded certificate and private key for resty.acme.clientclient.newsyntax: c, err = client.new(config) Create a ACMEv2 client. Default values for default_config = {
-- the ACME v2 API endpoint to use
api_uri = "https://acme-v02.api.letsencrypt.org/directory",
-- the account email to register
account_email = nil,
-- the account key in PEM format text
account_key = nil,
-- the account kid (as an URL)
account_kid = nil,
-- external account binding key id
eab_kid = nil,
-- external account binding hmac key, base64url encoded
eab_hmac_key = nil,
-- external account registering handler
eab_handler = nil,
-- storage for challenge
storage_adapter = "shm",
-- the storage config passed to storage adapter
storage_config = {
shm_name = "acme"
},
-- the challenge types enabled, selection of `http-01` and `tls-alpn-01`
enabled_challenge_handlers = {"http-01"},
-- select preferred root CA issuer's Common Name if appliable
preferred_chain = nil,
-- callback function that allows to wait before signaling ACME server to validate
challenge_start_callback = nil,
} If If CA requires External Account Binding, user can set
eab_handler = function(account_email)
-- do something to register an account with account_email
-- if err then
-- return nil, nil, err
-- end
return eab_kid, eab_hmac_key
end The following CA provider's EAB handler is supported by lua-resty-acme and user doesn't
need to implement their own
challenge_start_callback = function(challenge_type, challenge_token)
-- do something here
-- if we are good
return true
end See also Storage Adapters below. client:initsyntax: err = client:init() Initialize the client, requires availability of cosocket API. This function will login or register an account. client:order_certificatesyntax: err = client:order_certificate(domain,...) Create a certificate with one or more domains. Note that wildcard domains are not supported as it can only be verified by dns-01 challenge. client:serve_http_challengesyntax: client:serve_http_challenge() Serve http-01 challenge. A common use case will be to
put this as a content_by_* block for client:serve_tls_alpn_challengesyntax: client:serve_tls_alpn_challenge() Serve tls-alpn-01 challenge. See this section on how to use this handler. Storage AdaptersStorage adapters are used in fileFilesystem based storage. Sample configuration: storage_config = {
dir = '/etc/openresty/storage',
} If
shmLua shared dict based storage. Note this storage is volatile between Nginx restarts (not reloads). Sample configuration: storage_config = {
shm_name = 'dict_name',
} redisRedis based storage. The default config is: storage_config = {
host = '127.0.0.1',
port = 6379,
database = 0,
-- Redis authentication key
auth = nil,
} Redis >= 2.6.0 is required as this storage requires PEXPIRE. vaultHashicorp Vault based storage. Only KV V2 backend is supported. The default config is: storage_config = |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论