The tls_certificate and tls_private_key has chown by kumod and I am running using the following command: sudo KUMOD_LOG=kumod=debug /opt/kumomta/sbin/kumod --policy /opt/kumomta/etc/policy/init.lua --user kumod
The error I am getting is:
2023-10-30T22:08:46.109744Z DEBUG logger kumod::logging: waiting until deadline=None for a log record
2023-10-30T22:08:46.111633Z DEBUG main kumod::logging: Terminating a logger
2023-10-30T22:08:46.111661Z DEBUG main kumod::logging: Joining that logger
2023-10-30T22:08:46.111679Z DEBUG logger kumod::logging: LogCommand::Terminate received. Stopping writing logs
2023-10-30T22:08:46.111804Z DEBUG logger kumod::logging: Clearing any buffered files prior to completion
2023-10-30T22:08:46.112028Z DEBUG main kumod::logging: Joined -> Some(Ok(()))
Error: Initialization raised an error: call init callback: callback error
stack traceback:
[C]: in local 'poll'
[string "?"]:5: in function 'kumo.start_http_listener'
[string "/opt/kumomta/etc/policy/init.lua"]:54: in function <[string "/opt/kumomta/etc/policy/init.lua"]:13>
caused by: Permission denied (os error 13)
The permissions of the SSL files are:
-rw-r--r-- 1 kumod kumod 1521 Oct 30 21:21 cert.pem
-rw------- 1 kumod kumod 241 Oct 30 21:21 key.pem
Btw to anyone who is struggling with similar error, I set the permissions to CHMOD 600 and put it in an accessible place to kumod user in /home directory and chown it to kumod user. That resolved the issue there. I used a little script to copy files from Let’s Encrypt default location before I did this.
I am worried to use local SQLite DB because we would need to import new/changed records every 5 minutes and kumod user would probably be accessing the same DB file which is bad practice right? So thinking maybe we could achieve similar result with JSON file. We will use our default MySQL DB to export credentials to a JSON file every 5 minutes and let KumoMTA use that for doing AUTH checks for both SMTP and HTTP.
You could use either sqlite (provided that you use sqlite itself to update the db: it has transactions and supports multiple reader/writer processes) or a json file. You can use memoize - KumoMTA Docs to cache the lookups from either of those
Thanks for that, wez! Sorry just another question in relation to it. I’ve setup the SQLite with username and password credentials. Here’s my lua config. I am just not sure where to place in the init.lua file. Does it go inside the SMTP listener?
-- Custom authentication START
function sqlite_auth_check(user, password)
local db = sqlite.open '/home/simple.db'
local result = db:execute(
'select * from customer where email=? and apikey=?',
user,
password
)
-- if we got any rows, it was because a user+pass matched
return #result == 1
end
-- This creates a new function called `cached_sqlite_auth_check`
-- that remembers the results for a given set of parameters for up
-- to 5 minutes or up to 100 different sets of parameters
cached_sqlite_auth_check = kumo.memoize(sqlite_auth_check, {
name = 'sqlite_auth',
ttl = '5 minutes',
capacity = 100,
})
kumo.on('smtp_server_auth_plain', function(authz, authc, password)
return cached_sqlite_auth_check(authc, password)
end)
-- Custom authentication END
Ideally we want it to enforce AUTH checks under every situation for both HTTP and SMTP listeners since we opened relay to all using the following listener_domains.toml file
["*"]
# You can specify * as a default, overridden by any more explicitly defined domains.
# Since all options are false by default, this would only be needed to default
# An option to true for all domains.
relay_from_authz = true
log_oob = false
log_arf = false
and http_server_validate_auth_basic - KumoMTA Docs for HTTP
in both cases, username and password is verified in these events and the true/false status is passed back to the smtp_server_mesage_received or http_message_generated event respectively.
If it helps, this is from my own demo system authentication which uses basic auth for both SMTP and HTTP:
--[[ Adding basic Authentication (on disk) ]]--
-------------------------------------
-- FOR HTTP --
-- Use this to lookup and confirm a user/password
-- used with the http endpoint
kumo.on('http_server_validate_auth_basic', function(user, password)
local password_database = {
['myusername'] = 'This_is_a_Bad_Password',
}
if password == '' then
return false
end
return password_database[user] == password
end)
-- FOR SMTP --
-- Use this to lookup and confirm a user/password
-- used with the smtp endpoint
kumo.on('smtp_server_auth_plain', function(authz, authc, password)
local password_database = {
['myusername'] = 'This_is_a_Bad_Password',
}
if password == '' then
return false
end
return password_database[authc] == password
end)
-----------------------
This means that your received message code can be very clean. here is the HTTP example from my demo system:
local tenant = msg:get_first_named_header_value('x-tenant') or 'default'
msg:set_meta('tenant',tenant)
msg:remove_x_headers { 'x-tenant' }
-- SIGNING MUST COME LAST OR YOU COULD BREAK YOUR DKIM SIGNATURES
dkim_signer(msg)
end)
^^ You dont even need all that, I just like to use the tenant meta value to bucket “customers” or message types.
`For the auth_z section you have in listener_domains, that should work fine as it is (sort of). That is not really an “open_relay”, what it does is allow relay for any domain as long as the username and password are found in your DB. The only problem I see is that you don’t have it tied to a domain so user@password on domain x.com will also be able to send mail for y.com and abc.com as long as the credentials exist. I would highly recommend adding a section for each sending domain and add the specific users under each to make sure there is no bleeding of access.