Postgres递归查询SSH授权密钥路径

时间:2014-06-05 20:16:21

标签: postgresql recursion common-table-expression recursive-query

如何构建递归查询以帮助我找到可通过SSH公钥授权访问的所有服务器到服务器的跳转?

对于给定的SSH pubkey指纹,首先找到授权密钥的服务器/帐户列表。对于找到的每个服务器,迭代该服务器上的私钥,并找到每个那些的授权服务器/帐户列表。

重复此过程,直到死胡同,即授权密钥路径结束。每行返回一个完整的授权密钥路径(作为一个数组)。

简化示例:

CREATE TABLE sshkeys (
  server         text, -- server UUID
  username       text, -- authorized username
  privkey_owner  text, -- owner of private key
  fingerprint    text, -- SSH key fingerprint
  keytype        text, -- "public" or "private"
)

Server  Username  Owner  Fingerprint         Keytype
banana  root             key_id_james        public
banana  james            key_id_james        public
banana            root   key_id_root@banana  private
apple   root             key_id_root@banana  public
apple   fred      fred   key_id_fred         private
mango   fred             key_id_fred         public

James使用ID key_id_james的密钥访问root @ banana。从那里,root @ banana私钥被授权为root @ apple。在apple上,root可以访问key_id_fred,因此被授权使用fred @ mango。

所以最终,詹姆斯可以通过root访问香蕉和苹果访问Fred的芒果帐户。他还可以访问james @ banana。两个输出行将由{source,keyid,target}元素的数组组成,类似于:

{{NULL,   key_id_james,       root@banana},
 {banana, key_id_root@banana, root@apple},
 {apple,  key_id_fred,        fred@mango}},
{{NULL,   key_id_james,       james@banana}}

我计划添加应该考虑的限制和启发式方法,包括私钥是否加密以及给定用户是否具有对其他用户私钥的组或chmod访问权限(通过连接到数据库中的其他表)。但是,这应该很容易解决工作基础查询。

至于查询,我无法弄清楚如何执行辅助步骤,即:对于最初发现可通过给定密钥访问的每个服务器,迭代每个服务器上的所有私钥并递归。我没有比这个不起作用的查询更进一步:

WITH RECURSIVE initial_authkeys AS (
SELECT
  server, username, privkey_owner, fingerprint, keytype
FROM
  sshkeys
WHERE
  fingerprint = 'key_id_james' AND
  keytype = 'public'
UNION ALL
SELECT
  ak.server, ak.username, ak.privkey_owner, ak.fingerprint, ak.keytype
FROM
  sshkeys,
  initial_authkeys ak
WHERE
  sshkeys.fingerprint = ak.fingerprint AND
  sshkeys.keytype = 'private'
)
SELECT * FROM initial_authkeys;

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

使这项工作需要的是一个子查询表达式,用于查找授权给定pubkey的服务器上任何可用私钥的SSH指纹。下面是一个工作查询,其中包括一个基本的启发式方法,只有在用户具有对服务器的root访问权限时才能找到私钥。它可以扩展为验证私钥文件权限,组所有权等。

WITH RECURSIVE authkeys(server, username, fingerprint, level, auth_path) AS (
SELECT
  server, username, fingerprint, 1 AS level,
  ARRAY['Authorized to '||username||
  '@'||server||' using keyid='||fingerprint]
FROM
  sshkeys
WHERE
  fingerprint = 'key_id_james' AND keytype = 'public'
UNION
SELECT
  k.server, k.username, k.fingerprint, ak.level+1 AS level,
  auth_path || ARRAY['Authorized to '||k.username||
  '@'||k.server||' using keyid='||k.fingerprint]
FROM
  sshkeys k, authkeys ak
WHERE
  k.keytype = 'public' AND k.fingerprint IN (
    SELECT
      fingerprint
    FROM
      sshkeys k2
    WHERE
      k2.server = ak.server AND k2.keytype = 'private' AND
      ak.username = 'root'
  )
) SELECT * FROM authkeys;