如何以 myuser 身份进行 ssh,但在 /home/deployuser 中以部署用户身份运行所有 Capistrano 命令

Liz*_*rtz 5 ssh capistrano ruby-on-rails capistrano3

背景/问题

由于我绝对无法更改安全配置,因此我必须以联合用户 ssh 方式连接到我的所有设备myuser

我的盒子上需要部署的所有东西都归我所有deployuser,我绝对无法改变这一点。

myuser可以假设用户deployuser并拥有所有 sudo 权限。

最终,我希望我的 Capistrano 部署能够像我deployuser从一开始就 ssh 一样运行,因此每个命令都deployuser作为/home/deployuser.

我可以使用任何我想要的 Capistrano 版本,但现在我正在尝试使用 Capistrano 3。

测试设置

我创建了一个简单的 Capistrano 任务来测试是否可以对我知道属于 的文件执行操作deployuser

desc "Check that we can access everything"
task :check_permissions do
  on roles(:all) do |host|
    execute("whoami")
    execute("cp /tmp/file-owned-by-deploy-user /tmp/test-file")
  end
end
Run Code Online (Sandbox Code Playgroud)

编辑:上面的测试实际上并没有像人们预期的那样工作。我相信这是因为当您手动声明类似的内容时execute('command'),它会覆盖任何“以 X 用户身份执行此操作”的配置。更好的测试是运行您的cap environment deploy任务并查看失败的原因。

我尝试过的

sshkit-backends-netssh_global 根据他们的文档

我尝试的第一件事是sshkit-backends-netssh_global,它在他们的文档中说他们完全处理这个用例。

我将其添加到我的 Capfile 中,然后尝试将其添加到deploy.rb甚至高于我的任务定义,以防万一:

require 'sshkit/backends/netssh_global'

SSHKit::Backend::NetsshGlobal.configure do |config|
  config.owner        = 'deployuser'
  config.directory    = '/home/deployuser'
end
Run Code Online (Sandbox Code Playgroud)

这无论如何都是0效果。没有新的错误消息,只是同样的 Permission Denied,并且 whoami 返回 myuser。

在 Capistrano 3 中设置 :sshkit_backend

其次,我尝试:ssh_backend从 Capistrano 进行设置,我在本期中看到了 sshkit-backends-netssh_global

require 'sshkit/backends/netssh_global'

set :sshkit_backend, -> {
  SSHKit::Backend::NetsshGlobal.tap do |backend|
    backend.configure do |config|
      config.owner        = 'deployuser'
      config.directory    = '/home/deployuser'
    end
  end
}
Run Code Online (Sandbox Code Playgroud)

这表明它sshkit-backends-netssh_global不再与最新版本的 Capistrano 兼容。它使用的是已弃用的方法checkout。太讨厌了:

NoMethodError: undefined method `checkout' for #<SSHKit::Backend::ConnectionPool:0x007fae8340e3c0>
Run Code Online (Sandbox Code Playgroud)

我尝试降级到较低版本的 Capistrano,虽然解决了弃用问题,但它并没有神奇地使这些配置设置生效。不过我并没有挖得太深。

使用 SSHKit 中的“deployuser”进行测试

我有点觉得我在这里要疯了,因为当我尝试按照SSHKit 文档将我的任务包装为“用户”时,whoami它会运行deployuser,而 cp 命令仍然返回 Permission Denied。

所以也许我的测试脚本没有做我认为它正在做的事情。尽管如此,该命令可以复制/粘贴到服务器上并通过附加sudo -u deployuser.

在我上面的编辑中,我说这是因为我认为这样做execute('command')有点不同,并且没有考虑您的配置 - 它只是执行该操作。我认为。因此,这可能仍然适用于其他类型的任务(当然不适用于内部 Capistrano 任务)。

desc "Check that we can access everything"
task :check_permissions do
  on roles(:all) do
    as 'deployuser' do
      # this returns deployuser
      execute("whoami")

      # this throws permission denied
      execute("cp /tmp/file-owned-by-deploy-user /tmp/test-file")
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

使用 SSHKit.config.command_map

我尝试的另一种策略,其结果与上面的示例相同:

SSHKit.config.command_map = Hash.new do |hash, command|
  hash[command] = "sudo -u deployuser #{command}"
end
Run Code Online (Sandbox Code Playgroud)

whoami返回deployuser,但该cp命令仍然返回 Permission Denied。同样,这可能是因为execute实际上并不是我需要在这里测试的。

相关但未解决的 Stackoverflow 问题

一些相关问题

有人曾经让它工作过吗?有任何想法吗?

编辑:有用的东西(ish)

我一整天都在研究这个问题,这就是我到目前为止所得到的……这很糟糕,但我已经完成了基本的部署。

首先,虽然您大多数情况下都希望附加sudo -u deployuser到命令,但并非所有命令都如此。我本来还有其他几个在这里,但我把它归结为chmod不能作为我的运行deployuser

SSHKit.config.command_map = Hash.new do |hash, command|
  skipped_commands = [:chmod]

  if skipped_commands.include?(command)
    hash[command] = command
  else
    hash[command] = "sudo -u deployuser #{command}"
  end
end
Run Code Online (Sandbox Code Playgroud)

好吧,然后我意识到这并不适用于所有 Capistrano 案例,因为这些案例>>被插入到 Capistrano 端的几个 rake 任务中。

所以我为这两个任务编写了一个猴子补丁:

命名空间:部署做

  # MONKEY PATCH OH NO
  # =======================

  # you actually have to clear the old rake task 
  # for yours to overwrite Capistrano's
  Rake::Task['deploy:set_current_revision'].clear
  desc "IT'S MINE"
  task :set_current_revision  do
    on release_roles(:all) do
      within release_path do
        execute :echo, "\"$(sudo -u deployuser git rev-parse HEAD)\" | sudo -u deployuser tee REVISION"
      end
    end
  end

  Rake::Task['deploy:log_revision'].clear
  desc "Log details of the depl
  task :log_revision do
    on release_roles(:all) do
      within releases_path do
        execute :echo, %Q{"#{revision_log_message}" | sudo -u deployuser tee #{revision_log}}
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

调查正在进行中(我仍然需要实现部署的其余部分),但cap test_environment deploy在这些更改之后,现在已经完成了一个简单的工作。

另外,这是我的捆绑包,供将来发现此内容的人使用:

Gems included by the bundle:
  * activesupport (4.2.10)
  * airbrussh (1.3.0)
  * aws-partitions (1.56.0)
  * aws-sdk-core (3.14.0)
  * aws-sdk-ec2 (1.25.0)
  * aws-sigv4 (1.0.2)
  * bundler (1.16.0)
  * capistrano (3.10.1)
  * capistrano-bundler (1.3.0)
  * capistrano-rails (1.3.1)
  * coderay (1.1.2)
  * concurrent-ruby (1.0.5)
  * dogapi (1.28.0)
  * faraday (0.14.0)
  * i18n (0.9.3)
  * jmespath (1.3.1)
  * json (1.8.6)
  * method_source (0.9.0)
  * minitest (5.11.1)
  * multi_json (1.13.1)
  * multipart-post (2.0.0)
  * net-scp (1.2.1)
  * net-ssh (4.2.0)
  * pry (0.11.3)
  * rake (12.3.0)
  * slackbot (0.0.2)
  * sshkit (1.15.1)
  * sshkit-backends-netssh_global (0.1.1)
  * thread_safe (0.3.6)
  * tzinfo (1.2.4)
Run Code Online (Sandbox Code Playgroud)

再次编辑!

原始插件的作者昨天发布了这个补丁,它在 Capistrano 3.10 中适用于我,无需任何猴子补丁。

Ken*_*ter 1

我不是 capistrano 用户,但您可以使用 OpenSSH 功能来实现此目的。假设:

  1. Capistrano 正在连接到远程系统上的 OpenSSH ssh 服务器。
  2. ssh 会话正在使用 ssh 密钥进行身份验证
  3. 您可以更改远程 ssh 配置(尤其是myuser authorized_keys文件)

如果假设成立,则myuser每个远程系统上都有一个.ssh/authorized_keys文件,其中包含 capistrano 用于进行身份验证的公钥。您可以向该行添加一条指令,强制 ssh 服务器在使用该密钥时运行硬编码命令,而不是远程客户端请求的命令。这允许您为请求的命令插入自己的处理程序。

处理程序可以是一个简单的 shell 脚本。这尚未经过测试,但您应该明白:

#!/bin/sh
sudo -u deployuser $SSH_ORIGINAL_COMMAND
Run Code Online (Sandbox Code Playgroud)

将其存储在远程系统上的文件中,使其可执行,并将其设置为在authorized_keys文件中运行的命令。当 ssh 服务器代表远程客户端调用此命令时,它将SSH_ORIGINAL_COMMAND环境变量设置为远程客户端请求的命令字符串。

此处描述了authorized_keys文件。基本上,文件的每一行都指定一个可用于身份验证的密钥。一行看起来像这样:

ssh-rsa AAAAB3NzaC1yc2EAA...
Run Code Online (Sandbox Code Playgroud)

您可以在该行前面添加一个command=指令:

command=/home/myuser/run-as-deployuser ssh-rsa AAAAB3NzaC1yc2EAA...
Run Code Online (Sandbox Code Playgroud)

当使用此密钥进行身份验证时,ssh 服务器将调用请求的命令,而不是调用客户端请求的任何命令。正如我之前所说,SSH_ORIGINAL_COMMAND 环境变量将设置为客户端请求的命令。