How can i specify keytab file when connecting to postgres with golang pq using kerberos? - postgresql

I am currently using golang pq library to connect to postgres database. I am successfully connecting using kerberos principal, but i can't figure out where can i specify keytab file to use to. In the source code it kinda happens magically, using some third-party library. It actually works, but i need to know for sure how does it know where my keytab is stored, so it can request initial ticket.

Usually Kerberos clients do not directly use a keytab; they expect the initial ticket to be already acquired and present in the environment. That is, you're expected to kinit before running the program, and afterwards the client's GSSAPI library looks for the KRB5CCNAME environment variable, which points at a file containing the ticket cache left by kinit.
(Normally with MIT Kerberos or Heimdal it could be many other things besides a file... but the 'pq' library uses a very minimal pure-Go Kerberos implementation which only accepts a traditional file-based ccache. So be careful if Krb5 on your distro was set up to use 'DIR' or 'KEYRING' or 'KCM' cache types, those aren't going to work here.)
If the initial ticket isn't present, the MIT Krb5 implementation will in fact automatically use a keytab to acquire the ticket if the KRB5_CLIENT_KTNAME environment variable is pointing to one. Unfortunately, the 'pq' library doesn't use the system Kerberos library, so that won't work here either. (But it also wouldn't work if your OS was using Heimdal Kerberos; it's a MIT-specific extension.)
So the approach that will always work is to set KRB5CCNAME to a temporary path, then use either kinit or k5start to acquire a ticket from the keytab, before running your program. (The k5start tool will also keep automatically renewing or re-acquiring the ticket before it expires, without needing to use cron.)
Really, the whole krb_unix.go file is disappointing. If they can call the native SSPI on Windows, surely they could call the native GSSAPI on Linux...

Related

How to set preferred Kerberos/GSSAPI library in ssh config file?

I can connect to a remote host using Kerberos in PuTTY on Windows 10, but I cannot do the same thing in VS Code.
In PuTTY, there is a setting (see below) that specifies the order of GSSAPI libraries:
Since this answer states that Windows "has two Kerberos libraries (MIT KfW & Windows SSPI)", I suspect that VS Code is not defaulting to the correct, MIT Kerberos GSSAPI64.DLL library.
But I can't seem to find any answers online that shows how to specify the preference or order of such libraries in my ssh config file.
Any suggestions are welcome! Thanks in advance.
There is no way to do that.
When VSCode makes an SSH connection, it normally uses the ssh.exe program from OpenSSH rather than using PuTTY.
PuTTY has been deliberately written to load the libraries on the fly (to avoid the .exe having any hard dependencies), so its ability to configure the library paths is there "for free". That's not the case for OpenSSH, however, or even most other Kerberos-using programs – ssh.exe is "hard" linked to one specific library at compile time; it can dynamically load PKCS#11 backends but hasn't been programmed to dynamically load GSSAPI backends.
In addition, Windows SSPI actually provides a different API from that of GSSAPI – the core concepts and flows are the same, but the function names and prototypes differ quite a bit. Again, PuTTY supports both only because it was deliberately written to do so. Standard OpenSSH would only support GSSAPI, and while Microsoft has patched the "in-box" Win32-OpenSSH to use SSPI, it is still one or the other – you can't really make the Windows ssh.exe load MIT libgssapi instead.
There are several workarounds, though:
You can try installing a different OpenSSH build for Windows that does use GSSAPI from MIT Kerberos; perhaps either Cygwin OpenSSH, or the MSYS OpenSSH that's included with Git could work (if it has GSSAPI support at all).
You can try configuring VSCode to run PuTTY's command-line SSH client plink.exe instead of ssh.exe. This likely won't work for interactive shell sessions, but might be able to handle non-interactive ones (such as VSCode Remoting).
You can try using Windows SSPI, as it does not actually require domain membership to work as a Kerberos client – it's enough to save your Kerberos credentials in Windows:
cmdkey /add:*.example.com /user:sam#EXAMPLE.COM /pass
Note that if the realm is not running Active Directory, you also need to mark it as a "MIT realm" as an Administrator (the presence of a "realm flags" setting – even an empty one – is needed to prevent Windows from doing AD-specific Netlogon probes):
ksetup /addrealmflags EXAMPLE.COM TcpSupported
With the password stored, enabling GSSAPIAuthentication yes in your ~.ssh\config will allow Windows OpenSSH (as well as PuTTY with SSPI) to connect using Kerberos to any host matching the specified *.example.com.

Kinit autentication does not create klist ticket

I´ve been trying to connect to a HDFS server protected by Kerberos for days.
I alterady have have Kerberos for windows installed here. And it shows me the valid/active ticket.
But as I run 'Klist' on prompt, I see no tickets
If I run Kinit on prompt, it asks for my password and returns 'Authenticated to Kerberos v5' but still does not show me any klist ticket.
If I create a new tickt, using prompt or Kerberos GUI, it comes back showing me an active/valid ticket, but klist still does not.
I am trying to connect to hdfs using KerberosClient, but as I connect, somehow it does not "see" my active ticked (as klist too), so I got a connection denial.
I´ve setup the KRB5_CONFIG and KRB5CCNAME system variables to the folder exposed above.
What am I doing wrong?
Your system has two Kerberos libraries (MIT KfW & Windows SSPI) and two different klist tools:
the Windows klist.exe, which only shows the Windows LSA in-memory ticket cache that will be used by "Windows native" SSPI-based applications;
the MIT Kerberos klist.exe, which shows the file-based $KRB5CCNAME ticket cache that will be used by MIT "gssapi32.dll" GSSAPI-based applications.
(sometimes also the Java JRE klist.exe as well!)
If your HDFS client uses $KRB5CCNAME (e.g. if it uses GSSAPI via gssapi32.dll), then you need to run the MIT KfW klist.exe specifically. Use where.exe kinit to find out where it's located, then run it by full path.
On the other hand, if your HDFS client uses SSPI, then MIT KfW won't help you much – it can access tickets in the "MSLSA:" cache, but as far as I know it cannot put new tickets there. (It is possible to easily make SSPI acquire tickets for non-AD Kerberos services, but that's a different topic.)

need perl script to connect to database, but don't want the password in plain text [duplicate]

When a PHP application makes a database connection it of course generally needs to pass a login and password. If I'm using a single, minimum-permission login for my application, then the PHP needs to know that login and password somewhere. What is the best way to secure that password? It seems like just writing it in the PHP code isn't a good idea.
Several people misread this as a question about how to store passwords in a database. That is wrong. It is about how to store the password that lets you get to the database.
The usual solution is to move the password out of source-code into a configuration file. Then leave administration and securing that configuration file up to your system administrators. That way developers do not need to know anything about the production passwords, and there is no record of the password in your source-control.
If you're hosting on someone else's server and don't have access outside your webroot, you can always put your password and/or database connection in a file and then lock the file using a .htaccess:
<files mypasswdfile>
order allow,deny
deny from all
</files>
The most secure way is to not have the information specified in your PHP code at all.
If you're using Apache that means to set the connection details in your httpd.conf or virtual hosts file file. If you do that you can call mysql_connect() with no parameters, which means PHP will never ever output your information.
This is how you specify these values in those files:
php_value mysql.default.user myusername
php_value mysql.default.password mypassword
php_value mysql.default.host server
Then you open your mysql connection like this:
<?php
$db = mysqli_connect();
Or like this:
<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
ini_get("mysql.default.password"),
ini_get("mysql.default.host"));
Store them in a file outside web root.
For extremely secure systems we encrypt the database password in a configuration file (which itself is secured by the system administrator). On application/server startup the application then prompts the system administrator for the decryption key. The database password is then read from the config file, decrypted, and stored in memory for future use. Still not 100% secure since it is stored in memory decrypted, but you have to call it 'secure enough' at some point!
This solution is general, in that it is useful for both open and closed source applications.
Create an OS user for your application. See http://en.wikipedia.org/wiki/Principle_of_least_privilege
Create a (non-session) OS environment variable for that user, with the password
Run the application as that user
Advantages:
You won't check your passwords into source control by accident, because you can't
You won't accidentally screw up file permissions. Well, you might, but it won't affect this.
Can only be read by root or that user. Root can read all your files and encryption keys anyways.
If you use encryption, how are you storing the key securely?
Works x-platform
Be sure to not pass the envvar to untrusted child processes
This method is suggested by Heroku, who are very successful.
if it is possible to create the database connection in the same file where the credentials are stored. Inline the credentials in the connect statement.
mysql_connect("localhost", "me", "mypass");
Otherwise it is best to unset the credentials after the connect statement, because credentials that are not in memory, can't be read from memory ;)
include("/outside-webroot/db_settings.php");
mysql_connect("localhost", $db_user, $db_pass);
unset ($db_user, $db_pass);
If you are using PostgreSQL, then it looks in ~/.pgpass for passwords automatically. See the manual for more information.
Previously we stored DB user/pass in a configuration file, but have since hit paranoid mode -- adopting a policy of Defence in Depth.
If your application is compromised, the user will have read access to your configuration file and so there is potential for a cracker to read this information. Configuration files can also get caught up in version control, or copied around servers.
We have switched to storing user/pass in environment variables set in the Apache VirtualHost. This configuration is only readable by root -- hopefully your Apache user is not running as root.
The con with this is that now the password is in a Global PHP variable.
To mitigate this risk we have the following precautions:
The password is encrypted. We extend the PDO class to include logic for decrypting the password. If someone reads the code where we establish a connection, it won't be obvious that the connection is being established with an encrypted password and not the password itself.
The encrypted password is moved from the global variables into a private variable The application does this immediately to reduce the window that the value is available in the global space.
phpinfo() is disabled. PHPInfo is an easy target to get an overview of everything, including environment variables.
Your choices are kind of limited as as you say you need the password to access the database. One general approach is to store the username and password in a seperate configuration file rather than the main script. Then be sure to store that outside the main web tree. That was if there is a web configuration problem that leaves your php files being simply displayed as text rather than being executed you haven't exposed the password.
Other than that you are on the right lines with minimal access for the account being used. Add to that
Don't use the combination of username/password for anything else
Configure the database server to only accept connections from the web host for that user (localhost is even better if the DB is on the same machine) That way even if the credentials are exposed they are no use to anyone unless they have other access to the machine.
Obfuscate the password (even ROT13 will do) it won't put up much defense if some does get access to the file, but at least it will prevent casual viewing of it.
Peter
We have solved it in this way:
Use memcache on server, with open connection from other password server.
Save to memcache the password (or even all the password.php file encrypted) plus the decrypt key.
The web site, calls the memcache key holding the password file passphrase and decrypt in memory all the passwords.
The password server send a new encrypted password file every 5 minutes.
If you using encrypted password.php on your project, you put an audit, that check if this file was touched externally - or viewed. When this happens, you automatically can clean the memory, as well as close the server for access.
Put the database password in a file, make it read-only to the user serving the files.
Unless you have some means of only allowing the php server process to access the database, this is pretty much all you can do.
If you're talking about the database password, as opposed to the password coming from a browser, the standard practice seems to be to put the database password in a PHP config file on the server.
You just need to be sure that the php file containing the password has appropriate permissions on it. I.e. it should be readable only by the web server and by your user account.
An additional trick is to use a PHP separate configuration file that looks like that :
<?php exit() ?>
[...]
Plain text data including password
This does not prevent you from setting access rules properly. But in the case your web site is hacked, a "require" or an "include" will just exit the script at the first line so it's even harder to get the data.
Nevertheless, do not ever let configuration files in a directory that can be accessed through the web. You should have a "Web" folder containing your controler code, css, pictures and js. That's all. Anything else goes in offline folders.
Just putting it into a config file somewhere is the way it's usually done. Just make sure you:
disallow database access from any servers outside your network,
take care not to accidentally show the password to users (in an error message, or through PHP files accidentally being served as HTML, etcetera.)
Best way is to not store the password at all!
For instance, if you're on a Windows system, and connecting to SQL Server, you can use Integrated Authentication to connect to the database without a password, using the current process's identity.
If you do need to connect with a password, first encrypt it, using strong encryption (e.g. using AES-256, and then protect the encryption key, or using asymmetric encryption and have the OS protect the cert), and then store it in a configuration file (outside of the web directory) with strong ACLs.
Actually, the best practice is to store your database crendentials in environment variables because :
These credentials are dependant to environment, it means that you won't have the same credentials in dev/prod. Storing them in the same file for all environment is a mistake.
Credentials are not related to business logic which means login and password have nothing to do in your code.
You can set environment variables without creating any business code class file, which means you will never make the mistake of adding the credential files to a commit in Git.
Environments variables are superglobales : you can use them everywhere in your code without including any file.
How to use them ?
Using the $_ENV array :
Setting : $_ENV['MYVAR'] = $myvar
Getting : echo $_ENV["MYVAR"]
Using the php functions :
Setting with the putenv function - putenv("MYVAR=$myvar");
Getting with the getenv function - getenv('MYVAR');
In vhosts files and .htaccess but it's not recommended since its in another file and its not resolving the problem by doing it this way.
You can easily drop a file such as envvars.php with all environment variables inside and execute it (php envvars.php) and delete it. It's a bit old school, but it still work and you don't have any file with your credentials in the server, and no credentials in your code. Since it's a bit laborious, frameworks do it better.
Example with Symfony (ok its not only PHP)
The modern frameworks such as Symfony recommends using environment variables, and store them in a .env not commited file or directly in command lines which means you wether can do :
With CLI : symfony var:set FOO=bar --env-level
With .env or .env.local : FOO="bar"
Documentation :

SAML integration with Nagios

I am trying to integrate Nagios with SimpleSAMLPHP for SingleSignOn company wide.
I have installed simplesaml and Nagios on apache.
Looking out for configuration settings wherein I can specify SAML settings for Nagios.
Has anyone worked on it?
I don't think it's possible to do this without setting the Apache REMOTE_USER variable. The Nagios server is rendered by php and cgi scripts. The php scripts have a user variable attached to the Apache server's REMOTE_USER, and this can be removed to substitute for any other php variable. BUT, most of the functionality and restrictions are being processed in the cgi scripts.
Based on this issue on the Nagios Core GitHub repo, it doesn't look like they are planning on offering any other methods of passing information to the cgi scripts. Nagios X doesn't appear to offer any options either based on this forum post
For authentication in Nagios Core these may be the best options:
Continue using Htaccess Authentication
Wrap the entire application within another to protect it (but you lose per-user privileges)
Manually change the Apache REMOTE_USER variable when someone logs in (maybe a security risk if at all possible)
Migrate to Icinga, which does offer more authentication options
At my place of employment, we will likely be using #3 or #4 based on what's possible and more secure.

Does Greenplum support Kerberos Authentication between its nodes?

I need to "kerberize" our Greenplum cluster. One of the aspects of this is that I should kerberize the interface between the GP master and its Segment Hosts. I have been unable to determine if this is supported or not.
I have seen the parameters in the posgresql.conf file (krb_server_keyfile and krb_srvname) and have tried to set these, but it does not seem to work (Greenplum still works, it just does not appear the connection is kerberized).
I did this with hadoop and it was pretty straight forward, but, again, cannot figure out how to do it in GP or if it is even possible. Any ideas?
Thanks
Refer to Greenplum HD Manager 1.2 Installation and User Guide for instructions on how to deploy Kerberos. The document is related to Hadoop, but should serve for a general Greenplum install.
So... the answer, as near as I can tell is this:
First, for clarification, there are two places where I am required to "kerberize" GP. The first in master/slave connectivity. This turned out the be easy enough after I learned this communication is ssh based. I just switched the rsa/dsa generated passwordless authorization with Kerberos SSH. I am not sure this is really any more or less secure, but a requirement none-the-less. The second is locking down the administrative/jdbc access. This should easy, after all GP is based upon Postgres, I have have secured Postgres with Kerberos in the past. Unfortuntaly, GP is based upon Postgres 8.2. This was before GSS support for Kerberos was added to Postgres, and I cannot get this to work. I am not positive that it can. Maybe GP will upgrade to 8.4 (at a minimum) soon and I can try that.