【问题标题】:haskell amqp x509 client authhaskell amqp x509 客户端身份验证
【发布时间】:2017-12-11 23:43:21
【问题描述】:

我一直试图弄清楚如何将 x509 客户端身份验证与 Network.AMQP 一起使用。看来我需要创建一个AMQP.ConnectionOpts (其中包括)coTLSSettings 参数,如下所示:

import qualified Network.AMQP as AMQP
import Network.Connection
let opts = AMQP.ConnectionOpts {
    ..
  , coTLSSettings = Just $ AMQP.TLSCustom $ ...
}

在这一点上(省略号),在阅读了一些Network.Connection 文档(并且超出了我的深度)之后,它开始看起来非常复杂。而且我想知道我是否走在正确的道路上。

那么,我的问题是:如何轻松实现 x509 客户端身份验证?如果答案是“你不能”,有谁知道我在哪里可以找到使用 Network.Connection 模块的 x509 客户端身份验证示例?

【问题讨论】:

  • 所以你要对客户端进行身份验证,让服务器可以信任客户端?
  • 抱歉回复延迟。那是正确的。我会在今天下午的某个时候测试你的答案,让你知道结果如何。谢谢!
  • 如果您在使用此功能时遇到问题,请告诉我。我们也可以为此开始聊天。
  • 非常感谢您的提议。昨天下午我有一点时间,但还不够。然后今天耽误了。所以这是明天早上的首要任务。我的计划是尝试更多地将您的答案纳入我的工作,但如果失败,我将独立运行您的答案并在此处发布结果。再次感谢您的帮助。

标签: haskell amqp x509


【解决方案1】:

我们需要做两件事(对于我的测试环境来说是三件事)。

  1. 读取客户端凭据
  2. 将密码套件设置为defaultParamsClient 设置一个空密码套件(我不知道为什么。)。
  3. (对于我的测试环境)读取 CA 根证书,因此我们可以验证提供给我们的服务器证书。如果您不在测试环境中,则此证书应安装在系统证书存储中,并且应该是默认的。在这种情况下,您可以从程序中删除 CertificateStore 处理。

以下程序中的函数mkMyTLSSettings 替换了defaultParamsClient 结果中提到的部分。在用作onCertificateRequest 的函数中,您可以使用参数并根据参数values 分发不同的凭据。需要的值本身被读入 main 摆脱IO

对于以下程序,我修改了我在此answer 中找到的位。

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Data.Default.Class
import Network.AMQP
import Network.Socket.Internal (PortNumber)
import Network.TLS
import Network.TLS.Extra.Cipher (ciphersuite_default)
import Data.X509.CertificateStore (CertificateStore (..), readCertificateStore)
import Data.Maybe
import qualified Data.ByteString as BS
import qualified Network.Connection as C
import qualified Data.ByteString.Lazy.Char8 as BL

mkMyTLSSettings :: CertificateStore -> Credential -> C.TLSSettings
mkMyTLSSettings castore creds =
  let defaultParams = defaultParamsClient "127.0.0.1" BS.empty
      newClientShared = (clientShared defaultParams) { sharedCAStore = castore }
      newClientSupported = (clientSupported defaultParams) { supportedCiphers = ciphersuite_default }
      newClientHooks = (clientHooks defaultParams) { onCertificateRequest = \_ -> return (Just creds) }
  in C.TLSSettings $ defaultParams { clientShared = newClientShared
                                   , clientSupported = newClientSupported
                                   , clientHooks = newClientHooks
                                   }

myTLSSettings :: CertificateStore -> Credential -> TLSSettings
myTLSSettings castore creds = TLSCustom $ mkMyTLSSettings castore creds

myTLSConnectionOpts :: TLSSettings -> ConnectionOpts
myTLSConnectionOpts opts = ConnectionOpts
  [("127.0.0.1", 5671 :: PortNumber)]
  "/"
  [plain "guest" "guest"]
  (Just 131072)
  Nothing
  (Just 1)
  (Just opts)

testConnectionOpts :: ConnectionOpts -> IO ()
testConnectionOpts opts = do 
   conn <- openConnection'' opts
   chan <- openChannel conn
   declareQueue chan newQueue {queueName = "hello"}
   putStrLn "Trying to register callback"
   consumeMsgs chan "hello" Ack myCallback
   publishMsg chan "" "hello" newMsg {msgBody = (BL.pack "hello world"), msgDeliveryMode = Just Persistent}
   getLine
   closeConnection conn
   putStrLn "connection closed"

main :: IO ()
main = do
  testConnectionOpts defaultConnectionOpts
  putStrLn "trying with tls"
  castore <- maybe (error "couldn't read CA root Certificate") id <$> (readCertificateStore "/pathto/rootCA.pem")
  creds <- either error id <$> credentialLoadX509 "/pathto/client.pem" "/pathto/client.key"
  let opts = myTLSSettings castore creds
  testConnectionOpts (myTLSConnectionOpts opts)

myCallback :: (Message, Envelope) -> IO ()
myCallback (msg, env) = do
  putStrLn $ "received message: " ++ (BL.unpack $ msgBody msg)
  ackEnv env

作为gist

我在这个程序中的第一次通信是为了确保rabbitmq设置正确,我真的只遇到了TLS错误。如果您删除第 20 和 23 行,您可以测试您是否正确配置了 rabbitmq。在这种情况下,连接尝试应该会失败,因为我们没有提供客户端证书。

我创建了一个玩具 CA 用于测试,并颁发了用于 rabbitmq 服务器和客户端的证书。所以我有一个文件rootCA.pem,它存储了CA根证书和rabbitmq.keyrabbitmq.pem之类的文件,它们用于使用rabbitmq设置TLS。还为客户提供client.pemclient.key。我将 rabbitmq 配置为只为提供可信证书的客户端提供服务,通过设置 fail_if_no_peer_certtrue 并设置 {verify, verify_peer} 选项。

在我第一次尝试时,我遇到了LeafNotV3 的各种错误,这意味着我在第一次尝试时创建了我的rabbitmq.pem 错误。这是一个 X509.v1 证书,Network.TLS 默认不接受。我需要确保创建一个 X509.v3 证书,这是通过在颁发证书rabbitmq.pem 时启用某些扩展来完成的,请参阅here。我需要将选项 -req 添加到那里引用的命令行以使其工作。

【讨论】:

  • 嘿,我自己的解决方案还没有完全奏效;但我认为你的回答让我触手可及。非常感谢。希望你不介意我稍后再回来回答更多问题。 (虽然我希望不要)。再次感谢,周末愉快。
猜你喜欢
  • 2014-05-01
  • 2018-03-20
  • 1970-01-01
  • 2013-02-02
  • 2023-03-03
  • 2016-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多