Capistrano, Firewalls and Tunnel - ruby

We're using Capistrano to automate pushing new versions of a PHP application to a production server. The production server (we'll call it production) is public, while our repository server (we'll call it repo) sits behind our corporate firewall, along with our own machines.
Capistrano, as configured by default, won't work, as production can't talk to repo.
I was wondering if there was someway I could setup capistrano to SSH to repo first, then SSH to production opening a tunnel on a port that I can then use to SSH from production back to repo to pull the changes from SCM.
I just can't figure out how to set this up or figure out a better solution. Ideas?
Edit:
I've tried this:
role :web, "deploy.com"
namespace :deploy do
task :remote_tunnel do
run 'Creating SSH tunnel...' do |channel, stream, data|
ssh = channel.connection
ssh.forward.remote(22, 'server.com', 10000, '127.0.0.1')
ssh.loop {!ssh.forward.active_remotes.include?([10000, '127.0.0.1'])}
end
end
end
before "deploy:update_code", "deploy:remote_tunnel"
But I keep getting this error:
failed: "sh -c 'Creating SSH tunnel...'" on deploy.com

Here's are 2 ways to accomplish it.
1st way
not sure if you've seen this thread?
https://groups.google.com/forum/?fromgroups=#!topic/capistrano/RVwMim-qnMg
It makes use of the net-ssh-gateway library, but creates copies of the local forwarding methods but they're geared for remote access.
class Net::SSH::Gateway
# Opens a SSH tunnel from a port on a remote host to a given host and port
# on the local side
# (equivalent to openssh -R parameter)
def open_remote(port, host, remote_port, remote_host = "127.0.0.1")
ensure_open!
#session_mutex.synchronize do
#session.forward.remote(port, host, remote_port, remote_host)
end
if block_given?
begin
yield [remote_port, remote_host]
ensure
close_remote(remote_port, remote_host)
end
else
return [remote_port, remote_host]
end
rescue Errno::EADDRINUSE
retry
end
# Cancels port-forwarding over an open port that was previously opened via
# open_remote.
def close_remote(port, host = "127.0.0.1")
ensure_open!
#session_mutex.synchronize do
#session.forward.cancel_remote(port, host)
end
end
end
2nd way
Outlined in an answer to this SO question:
Is it possible to do have Capistrano do a checkout over a reverse SSH tunnel?
This technique is very similar to the 1st way. First you need to create 2 paths to the repository:
# deploy.rb
set :local_repository, "ssh://git#serverbehindfirewall/path/to/project.git"
set :repository, "ssh://git#localhost:9000/path/to/project.git"
Then before you deploy you'll need to setup the remote forward:
% ssh -R 9000:serverbehindfirewall:22 deploybot#deployserver.com
# CTRL + C + A (Screen) or ⌘ + T (Terminal.app) to open new tab
Followed by your deploy:
% cap HOSTFILTER=deployserver.com deploy # HOSTFILTER reduces set to specified host. Only useful if you have multiple servers.
See this answer to that SO question for more details:
https://stackoverflow.com/a/3953351/33204

Using Capistrano 3.x, the following works for me:
namespace :deploy do
desc "Open SSH Tunnel to GitLab"
task :open_tunnel do
on roles(:app) do
info "Opening SSH Remote Tunnel..."
self.send(:with_ssh) do |ssh|
# ssh -R 9000:192.168.1.123:22
ssh.forward.remote(22, "192.168.1.123", 9000)
end
end
end
before "deploy:check", "deploy:open_tunnel"
end
Please note that ssh.forward.remote expects parameters in a different order than ssh -R, the above is equivalent to ssh -R 9000:192.168.1.123:22
This task calls a private method, if anyone knows an official way to get the access Capistrano's ssh connection, please comment or edit.
Edit: Also see the section Tunneling and other related SSH themes of SSHKit's README

Related

Having problems running shellinabox on my Ubuntu 16.04

I have been trying to use shellinabox. I cloned the github repo below and followed the steps mentioned.
https://github.com/shellinabox/shellinabox
My /etc/default/shellinabox file is like below:-
# Should shellinaboxd start automatically
SHELLINABOX_DAEMON_START=1
# TCP port that shellinboxd's webserver listens on
SHELLINABOX_PORT=4200
# Parameters that are managed by the system and usually should not need
# changing:
# SHELLINABOX_DATADIR=/var/lib/shellinabox
# SHELLINABOX_USER=shellinabox
# SHELLINABOX_GROUP=shellinabox
# Any optional arguments (e.g. extra service definitions). Make sure
# that that argument is quoted.
SHELLINABOX_ARGS="--o-beep"
All steps were same for me except the deb package installation which I downloaded from a resource which is shellinabox_2.20_armel.deb which i kept in the root folder.
On the other hand I tried all steps in below link too :-
https://askubuntu.com/questions/414930/access-webpage-through-ssh
and have watched the below video from youtube:-
https://www.youtube.com/watch?v=2viORNwxNTY
But I am not able to run the localhost using my IP address to access it. https://myipaddress:4200/
When I try to access the url in web browser I see
This site can’t be reached.
myipaddress refused to connect.
Try:
Checking the connection
Checking the proxy and the firewall
ERR_CONNECTION_REFUSED
What am I missing or doing wrong?

Capifony forward_agent not working. Asks for GitHub password and fails

I am using capifony to deploy a symfony2 web app onto Ubuntu. I have the following in my deploy.rb:
set :repository, "git#github.com:Username/Repo.git"
set :branch, "develop"
set :scm_verbose, true
set :deploy_via, :remote_cache
default_run_options[:pty] = true
set :ssh_options, {:forward_agent => true}
ssh_options[:keys] = ["/Users/myuser/Sites/file.pem"]
ssh_options[:auth_methods] = ["publickey"]
Capifony is able to ssh in but then asks for a GitHub password during the deploy. I enter the password correctly but it then give me the following authentication fail error:
remote: Invalid username or password
fatal: Authentication failed for 'https://UserName#github.com/UserName/Repo.git/'
I don't know why it is asking for my Github password, and why it doesn't use agent forwarding to ssh to github?
I have added my public key from the server to GitHub but I am a bit confused about these keys, and my local keys? does it forward my local key or does it use the server one? What permissions do I need to set etc?
I am using capifony v2.8.6
I recently had to reinstall ruby and capifony die to upgrading to El Capitan which stopped capifony from working altogether. This is when my problems started.
I am deploying to Ubuntu 14.04
I have tried editing /etc/ssh/ssh_config on the server and adding
ForwardAgent yes
Then restarting ssh, but this has no effect.
Thanks
I do not use Capifony anymore and cannot comment yet so I try to answer :)
First, if you deploy from your local machine (your Mac), check :
your ssh-agent is started,
you can git clone one of your github repo
you can ssh to your Ubuntu server
Then you could just set this two line below.
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
No need to set other ssh_options nor to tweak you ssh server config , it might be very confusing.
Second, you can test if ssh forwarding is working for the selected environment by creating a simple rake tasks inside your project :
namespace :ssh do
desc "Check if agent forwarding is working"
task :forwarding do
on roles(:all) do |h|
if test("env | grep SSH_AUTH_SOCK")
info "Agent forwarding is up to #{h}"
else
error "Agent forwarding is NOT up to #{h}"
end
end
end
end
And test with a cap [env] ssh:forwarding
Finally, if you reinstalled ruby/capifony recently, try to make the switch to Capistrano v3 and its Symfony gem instead, it really worth a try.

Adding local ssh option to Capistrano task

I have a Capistrano deployment script that exports my local database to a remote server and vice versa.
Here is one such task...
desc "Imports the remote database into your local environment"
task :pull do
# Create dump of remote db
invoke 'db:backup'
on roles(:app) do
run_locally do
# Create dump of current local db
execute "mysqldump -u #{fetch(:local_db_user)} -p#{fetch(:local_db_password)} #{fetch(:local_db_name)} > #{fetch(:local_backup_file)}"
# Import remote db into local
execute "mysql -u #{fetch(:local_db_user)} -p#{fetch(:local_db_password)} #{fetch(:local_db_name)} < db_backups/#{fetch(:curr_stage)}/#{fetch(:backup_filename)}.sql"
end
end
Rake::Task['db:cleanup_local'].execute
end
However I'm running a virtual host (Vagrant box) locally so to do local database tasks need to SSH into it.
What I want to do is add an option in the Capistrano options that if present will add something like ssh vagrant#192.168.10.10 to the start of the mysqldump and mysql commands and if it's not defined not add anything.
So I would want my local database connection details to look something like
set :local_db_host, "127.0.0.1"
set :local_db_name, "database_dev"
set :local_db_user, "homestead"
set :local_db_password, "secret"
set :local_ssh, "vagrant#192.168.10.10"
How could I add this option within the Capistrano task in a tidy way? Much thanks for any help.

Capistrano error : could not connect to ssh-agent

I'm using Bedrock with Capistrano deploys.
When I use command bundle exec cap staging deploy:check I get an authentication error :
...
D, [2015-05-09T15:39:53.878464 #15636] DEBUG -- net.ssh.authentication.session[1e34a58]: trying publickey
D, [2015-05-09T15:39:53.878464 #15636] DEBUG -- net.ssh.authentication.agent[1e30d2c]: connecting to ssh-agent
E, [2015-05-09T15:39:53.879447 #15636] ERROR -- net.ssh.authentication.agent[1e30d2c]: could not connect to ssh-agent
E, [2015-05-09T15:39:53.879447 #15636] ERROR -- net.ssh.authentication.session[1e34a58]: all authorization methods failed (tried publickey)
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as deploy#SERVER_IP: Authentication failed for user deploy#SERVER_IP
Tasks: TOP => git:check => git:wrapper
Capistrano could not connect to ssh-agent on my server.
But I can log in on my server via SSH like this ssh deploy#SERVER_IP without password. I dit all the instructions in Capistrano Authentication & Authorisation Docs page, so I can use command like me#localhost $ ssh deploy#one-of-my-servers.com 'hostname; uptime'.
If I enter command ssh -A deploy#SERVER_IP 'env | grep SSH_AUTH_SOCK' I get result
SSH_AUTH_SOCK=/tmp/ssh-UweQkw7578/agent.7578
Here is my deploy.rb file :
set :application, 'APP'
set :repo_url, 'URL'
set :branch, :master
set :tmp_dir, '~/tmp'
set :log_level, :info
set :linked_files, fetch(:linked_files, []).push('.env')
set :linked_dirs, fetch(:linked_dirs, []).push('web/app/uploads')
Here is my staging.rb file :
set :stage, :staging
set :deploy_to, -> { "/var/www/vhosts/project/dev" }
server 'SERVER_IP', user: 'deploy', roles: %w{web app}
set :ssh_options, {
user: 'deploy',
keys: %w('/c/Users/alexander/.ssh/id_rsa'),
forward_agent: true,
auth_methods: %w(publickey),
verbose: :debug
}
fetch(:default_env).merge!(wp_env: :staging)
Apache's agent forwarding agent instruction is enabled in sshd_config file : AllowAgentForwarding yes
What should do with my config files to make my deploy work?
Windows 8.1
Ruby 2.2.0
Capistrano 3.2.1
Git Bash
OK so I had the same issue, and I spent way too long working out exactly what is happening here, and the upshot is -
for ruby on windows, you must run pagent, not ssh-agent, for Capistrano and agent forwarding to work - in fact pretty much any tool that uses the Ruby net-ssh library on Windows.
And I dont think that will change, at least not for a while.
Agent Forwarding
See An Illustrated Guide to SSH Agent Forwarding for more about agent forwarding, and how the key challenge ends back up on our workstation.
Terminology
workstation - the machine (Windowa server/desktop/laptop) our SSH
client software is running from, and, most importantly, our PKI
private key is stored on (with or without a passphrase)
deployment node - the target of our Capistrano deployment task, most
like defined in the 'server' key in our config/deploy.rb, or
config/deploy/.rb file
git repo - where we will pull the code from, first queried via "git
ls-remote" - we will access this git repo via SSH, and the deployment
node will use agent forwarding to pass the key challenge back to the
workstation
SSH client software - how we reach out to sshd on remote servers, and
which has access to our private key. Might be putty, an OpenSSH ssh
client or the net-ssh library in Ruby.
Setup
I have a Windows 7 workstation box, with Git-Bash, and its OpenSSH ssh client, plus the script from Joe Reagle that sets up some environmental variables that say which port and pid the ssh-agent is operating on.
I also have Putty and Pageant, but I focussed, initially, on just the OpenSSH/Git-Bash tools.
I have set up passwordless ssh from the workstation to the deployment node, I have the ssh-agent running, I have my key added through ssh-add, and I have my public key registered as a read-only access key to the git repo.
Basics
So we are trying to use SSH agent forwarding to have Capistrano pull from our Git repo onto our deployment node.
Now we can test this all ourselves by setting up our public SSH key on the deployment node and using, say, the OpenSSH ssh client, to confirm we have passwordless ssh working. Then we can setup ssh-agent by
starting ssh-agent and setting the SSH_AUTH_SOCK and SSH_AGENT_PID as required.
adding our private key to the ssh-agent via ssh-add
add our public key as an authorised key to the git repo
ssh to the deployment node, and from there do a "git ls-remote git#" (or a ssh -T git#)
If everything is setup correctly, this will all work, and so we will think "ok I can do a 'cap deploy:check'" - and it will fail.
What Went Wrong
We will get an error
"Error reading response length from authentication socket"
Who is telling us this ? It isnt immediately clear, but it
isn't the git repo
it isnt the git client on the deployment node
it isnt the sshd daemon on the deployment node, that wants to pass the key challenge back to the workstation.
Its the Ruby ssh client library on the workstation.
How do we know this
In the ssh_options hash in the deploy.rb file, we add the following :
verbose: :debug
When we do this we see this message
Pageant not running.
Why is Capistrano trying to use Pageant instead of ssh-agent
When running via Capistrano, the ssh client is different to the one you used when verifying things by hand.
When verifying by hand, it was an OpenSSH ssh client. Now it is the net-ssh library in Ruby.
And on Windows, net-ssh has these lines
if Net::SSH::Authentication::PLATFORM == :win32
require 'net/ssh/authentication/pageant'
end
or
case Net::SSH::Authentication::PLATFORM
when :java_win32
require 'net/ssh/authentication/agent/java_pageant'
else
require 'net/ssh/authentication/agent/socket'
So loading pageant is hard-coded into net-ssh. It doesnt even try to see if you are running under a unix-like shell (like git-bash or cygwin), and to then use the unix-domain ssh-agent SSH_AUTH_SOCK
At present net-ssh doesnt try to open a unix-domain named socket. In theory I think it could, through the UNIXSocket class in the stdlib. But I haven't experimented with that on a Windows machine yet.

mina gem deploy through gateway

I am using the mina gem to deploy.
I have to go through a gateway in order to connect to my server.
I know that capistrano enables it.
Does any one know this config in mina?
I don't believe mina supports this; certainly, the source code doesn't indicate such an option. I was experimenting with using the set :ssh_options, '' syntax, but mina appends -t to the end of the command chain, which then gets sent to the wrong server. Considered changing the mina code, but it's probably simpler to shift the gateway connection to your local ssh client itself, and possibly to use the set :forward_agent, true command. To do such, you'd set something like this in your ~/.ssh/config:
Host finaldestination.example.com
ProxyCommand ssh user#gateway.example.com nc %h 22
ForwardAgent yes
Testing using my localhost as a gateway seems to show this as workable.
Hope this helps - although I realise it isn't exactly what you were asking. :)

Resources