Verify rabbitmq credentials are valid - python

I'd like to write a simple smoke test that runs after deployment to verify that the RabbitMQ credentials are valid. What's the simplest way to check that rabbitmq username/password/vhost are valid?
Edit: Preferably, check using a bash script. Alternatively, using a Python script.

As you haven't provided any details about language, etc.:
You could simply issue a HTTP GET request to the management api.
$ curl -i -u guest:guest http://localhost:15672/api/whoami
See RabbitMQ Management HTTP API

Here's a way to check using Python:
#!/usr/bin/env python
import socket
from kombu import Connection
host = "localhost"
port = 5672
user = "guest"
password = "guest"
vhost = "/"
url = 'amqp://{0}:{1}#{2}:{3}/{4}'.format(user, password, host, port, vhost)
with Connection(url) as c:
try:
c.connect()
except socket.error:
raise ValueError("Received socket.error, "
"rabbitmq server probably isn't running")
except IOError:
raise ValueError("Received IOError, probably bad credentials")
else:
print "Credentials are valid"

You could try with rabbitmqctl as well,
rabbitmqctl authenticate_user username password
and check the return code in Bash.

using Python:
>>> import pika
>>> URL = 'amqp://guest:guest#localhost:5672/%2F'
>>> parameters = pika.URLParameters(URL)
>>> connection = pika.BlockingConnection(parameters)
>>> connection.is_open
True
>>> connection.close()

Related

How to execute remote commands via SSH through authenticated HTTP Proxy?

I am posting the question and the answer, I found, as well, incase it would help someone. The following were my minimum requirements:
1. Client machine is Windows 10 and remote server is Linux
2. Connect to remote server via SSH through HTTP Proxy
3. HTTP Proxy uses Basic Authentication
4. Run commands on remote server and display output
The purpose of the script was to login to the remote server, run a bash script (check.sh) present on the server and display the result. The Bash script simply runs a list of commands displaying the overall health of the server.
There have been numerous discussions, here, on how to implement HTTP Proxy or running remote commands using Paramiko. However, I could not find the combination of both.
from urllib.parse import urlparse
from http.client import HTTPConnection
import paramiko
from base64 import b64encode
# host details
host = "remote-server-IP"
port = 22
# proxy connection & socket definition
proxy_url = "http://uname001:passw0rd123#HTTP-proxy-server-IP:proxy-port"
url = urlparse(proxy_url)
http_con = HTTPConnection(url.hostname, url.port)
auth = b64encode(bytes(url.username + ':' + url.password,"utf-8")).decode("ascii")
headers = { 'Proxy-Authorization' : 'Basic %s' % auth }
http_con.set_tunnel(host, port, headers)
http_con.connect()
sock = http_con.sock
# ssh connection
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(hostname=host, port=port, username='remote-server-uname', password='remote-server-pwd', sock=sock)
except paramiko.SSHException:
print("Connection Failed")
quit()
stdin,stdout,stderr = ssh.exec_command("./check")
for line in stdout.readlines():
print(line.strip())
ssh.close()
I would welcome any suggestions to the code as I am a network analyst and not a coder but keen to learn and improve.
I do not think that your proxy code is correct.
For a working proxy code, see How to ssh over http proxy in Python?, particularly the answer by #tintin.
As it seems that you need to authenticate to the proxy, after the CONNECT command, add a Proxy-Authorization header like:
Proxy-Authorization: Basic <credentials>
where the <credentials> is base-64 encoded string username:password.
cmd_connect = "CONNECT {}:{} HTTP/1.1\r\nProxy-Authorization: Basic <credentials>\r\n\r\n".format(*target)

Paramiko SSH failing with "Server '...' not found in known_hosts" when run on web server

I am trying to use Paramiko to make an SSH communication between 2 servers on a private network. The client server is a web server and the host server is going to be a "worker" server. The idea was to not open up the worker server to HTTP connections. The only communication that needs to happen, is the web server needs to pass strings to a script on the worker server. For this I was hoping to use Paramiko and pass the information to the script via SSH.
I set up a new user and created a test script in Python 3, which works when I run it from the command line from my own user's SSH session. I put the same code into my Django web app, thinking that it should work, since it tests OK from the command line, and I get the following error:
Server 'worker-server' not found in known_hosts
Now, I think I understand this error. When performing the test script, I was using a certain user to access the server, and the known hosts information is saved to ~/.ssh/known_hosts even though the user is actually a 3rd party user created just for this one job. So the Django app is running under a different user who doesn't find the saved known hosts info because it doesn't have access to that folder. As far as I can tell the user which Apache uses to execute the Django scripts doesn't have a home directory.
Is there a way I can add this known host in a way that the Django process can see it?
Script:
import paramiko
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('worker-server', 22, 'workeruser', 'workerpass')
code = "123wfdv"
survey_id = 111
stdin, stdout, stderr =
client.exec_command('python3 /path/to/test_script/test.py %s %s' % ( code, survey_id ))
print( "ssh successful. Closing connection" )
stdout = stdout.readlines()
client.close()
print ( "Connection closed" )
output = ""
for line in stdout:
output = output + line
if output!="":
print ( output )
else:
print ( "There was no output for this command" )
You can hard-code the host key in your Python code, using HostKeys.add:
import paramiko
from base64 import decodebytes
keydata = b"""AAAAB3NzaC1yc2EAAAABIwAAAQEA0hV..."""
key = paramiko.RSAKey(data=decodebytes(keydata))
client = paramiko.SSHClient()
client.get_host_keys().add('example.com', 'ssh-rsa', key)
client.connect(...)
This is based on my answer to:
Paramiko "Unknown Server".
To see how to obtain the fingerprint for use in the code, see my answer to:
Verify host key with pysftp.
If using pysftp, instead of Paramiko directly, see:
PySFTP failing with "No hostkey for host X found" when deploying Django/Heroku
Or, as you are connecting within a private network, you can give up on verifying host key altogether, using AutoAddPolicy:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(...)
(This can be done only if you really do not need the connection to be secure)

Ping server in Python without root permissions

I have a python script, that is working only if my server is available. So before the script is beginning, i want to ping my server or rather checking the availability of the server.
There are already some related SO questions.
E.g
pyping module
response = pyping.ping('Your IP')
if response.ret_code == 0:
print("reachable")
else:
print("unreachable")
ping process in python
response = os.system("ping -c 1 " + hostname)
These answers works well, but only as ROOT user!
When i use this solutions as a common user i get the following error message:
ping: Lacking privilege for raw socket.
I need a solution, that i can do that as a common user, because i run this script in a jenkins job and have not the option to run in as root.
Would trying to perform a HTTP HEAD request, assuming the machine has a http server running, suffice?
from http.client import HTTPConnection # python3
try:
conn = HTTPConnection(host, port, timeout)
conn.request("HEAD", "/")
conn.close()
# server must be up
except:
# server is not up, do other stuff

paramiko allows sftp connection without key

I was running the demo_sftp.py file from the demo folder in the paramiko github. I was stepping through it in PyDev and expected to get an error because I didn't have a key to the server I was trying to connect to but I got the print statement saying that the script couldn't open the host key file and then it went ahead and did the get and put.
Here's a code snippet.
try:
host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
except IOError:
try:
# try ~/ssh/ too, because windows can't have a folder named ~/.ssh/
host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
except IOError:
print '*** Unable to open host keys file'
host_keys = {}
if host_keys.has_key(hostname):
hostkeytype = host_keys[hostname].keys()[0]
hostkey = host_keys[hostname][hostkeytype]
print 'Using host key of type %s' % hostkeytype
# now, connect and use paramiko Transport to negotiate SSH2 across the connection
try:
t = paramiko.Transport((hostname, port))
t.connect(username=username, password=password, hostkey=hostkey)
sftp = paramiko.SFTPClient.from_transport(t)
# dirlist on remote host
dirlist = sftp.listdir('.')
print "Dirlist:", dirlist
I really expected it to go to the except on the t.connect line because hostkey is NoneType.
When I open an ssh connection with
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect('.'.join([self.name, self.domain]),
username=self.username, password=self.password)
stdin, stdout, stderr = ssh.exec_command("ps aux | grep Xvnc | wc -l")
I have to have the AutoAddPolicy() line or it fails. So what's the difference? Obviously I'm just learning this but I thought that sftp would be just as strict as ssh.
It looks like this is an acceptable practice.
Comment from Transport.connect
'''
Negotiate an SSH2 session, and optionally verify the server's host key
and authenticate using a password or private key. This is a shortcut
for L{start_client}, L{get_remote_server_key}, and
L{Transport.auth_password} or L{Transport.auth_publickey}. Use those
methods if you want more control.
You can use this method immediately after creating a Transport to
negotiate encryption with a server. If it fails, an exception will be
thrown. On success, the method will return cleanly, and an encrypted
session exists. You may immediately call L{open_channel} or
L{open_session} to get a L{Channel} object, which is used for data
transfer.
#note: If you fail to supply a password or private key, this method may
succeed, but a subsequent L{open_channel} or L{open_session} call may
fail because you haven't authenticated yet.
'''
Comment from SSHClient.connect
'''
Connect to an SSH server and authenticate to it. The server's host key
is checked against the system host keys (see L{load_system_host_keys})
and any local host keys (L{load_host_keys}). If the server's hostname
is not found in either set of host keys, the missing host key policy
is used (see L{set_missing_host_key_policy}). The default policy is
to reject the key and raise an L{SSHException}.
'''
Maybe it is due to the fact that sftp can only transport data while ssh can run terminal commands. I do find it interesting that a man-in-the-middle attack doesn't seem to be a concern.
You can use below syntax
import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection(hostname, port=port, username=user_id, password=password,
cnopts=cnopts) as sftp:
with sftp.cd(self.directory): # temporarily chdir to public
sftp.put(filepath)

paramiko no existing session exception

Using the python interactive shell and openssh running locally, I keep getting an "No existing session" exception using paramiko. My code is below.
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('localhost',username=name,password=pw)
Results in:
No handlers could be found for logger "paramiko.transport"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/paramiko-1.7.7.1-py2.6.egg/paramiko/client.py", line 332, in connect
self._auth(username, password, pkey, key_filenames, allow_agent, look_for_keys)
File "/usr/local/lib/python2.6/dist-packages/paramiko-1.7.7.1-py2.6.egg/paramiko/client.py", line 493, in _auth
raise saved_exception
paramiko.SSHException: No existing session
I was able to connect previously, but had been trying to adjust this to allow for key based authorization. That failed, and since then I have not been able to connect locally. I have tried restarting openssh, and have connected to another server successfully. After searching through here, all I have found are mentions of authorization exceptions, which does not appear to be the case here.
As you already have password you don't need to talk to agent or look for private keys stored on your machine. So try passing extra parameters allow_agent, look_for_keys:
ssh.connect('localhost',username=name,password=pw,allow_agent=False,look_for_keys=False)
I had a spare public key with a key pass phrase in my ssh-add list. Once I removed it, I was able to execute my paramiko based script properly.
To list:
ssh-add -l
To delete all:
ssh-add -D
To re-add:
ssh-add /FULL/PATH/TO/id_rsa
https://bugs.launchpad.net/paramiko/+bug/912123
Which OS are you using?
Maybe you can check your env variable:
SSH_AUTH_SOCK
for "connect", it will try to use ssh agent.
in agent.py
self.conn = None
self.keys = ()
if ('SSH_AUTH_SOCK' in os.environ) and (sys.platform != 'win32'):
conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
conn.connect(os.environ['SSH_AUTH_SOCK'])
except:
# probably a dangling env var: the ssh agent is gone
return
self.conn = conn
elif sys.platform == 'win32':
import win_pageant
if win_pageant.can_talk_to_agent():
self.conn = win_pageant.PageantConnection()
else:
return
Just got the same error ERROR:SSHException('No existing session',) but since it was in a clean docker container, there was no ssh-agent.
After some hours of debugging, I found a different solution: it can happen when there is a timeout during key exchange! In my case, the ssh server is a router over GSM link, which is very slow.
You can enable debug on paramiko with:
logging.getLogger("paramiko").setLevel(logging.DEBUG)
And if you see the exception between the Connected and the Switch to new keys ..., it means the timeout was during the key exchange. In this case, you have to set timeout to a bigger value! (documentation says timeout is only for TCP connect, but in fact, it is also for the whole negotiation before auth!)
In my case ,I have try use allow_agent=False,look_for_keys=False, but not work .
I ssh to a 2G device, so timeout=10 is Ok, timeout=3 get" Unable to establish SSH connection: No existing session". Not timeout except.
So try timeout= a long time,if connect to a not establish ssh.
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip,22,username,passwd,timeout=10,allow_agent=True,look_for_keys=True)
print ('%s\tOK\n'%(ip) )
except socket.timeout:
print ("%s time out"%(ip))
except paramiko.AuthenticationException:
print("Authentication failed, please verify your credentials: %s"%(ip))
except paramiko.SSHException as sshException:
print("Unable to establish SSH connection: %s" %(sshException))
except paramiko.BadHostKeyException as badHostKeyException:
print("Unable to verify server's host key: %s" %(badHostKeyException))
finally:
ssh.close()
Replace 'localhost' by '127.0.0.1'.

Categories