<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>Full · 仁才德</title>
    <link>https://jared.lynskey.co.nz/zh-cn/tags/full/</link>
    <description>关于软件工程与研发团队领导力的短文——绩效评估、招聘与团队扩张、CI/CD、DevOps 监控、智能体 AI。写于首尔。</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <copyright>© 2026 仁才德</copyright>
    <lastBuildDate>Wed, 28 Oct 2026 00:00:00 +1300</lastBuildDate>
    <atom:link href="https://jared.lynskey.co.nz/zh-cn/tags/full/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>SSH登录通知发到Slack：用PAM和Webhook实现</title>
      <link>https://jared.lynskey.co.nz/zh-cn/posts/2021/2021-12-14-ssh-log/</link>
      <guid isPermaLink="true">https://jared.lynskey.co.nz/zh-cn/posts/2021/2021-12-14-ssh-log/</guid>
      <pubDate>Tue, 14 Dec 2021 11:30:03 +0000</pubDate>
      <dc:creator>Jared Lynskey</dc:creator>
      <category>dev</category>
      <category>full</category>
      <category>stack</category>
      <category>useful</category>
      <category>slack</category>
      <category>ssh</category>
      <category>proactive</category>
      <category>ops</category>
      <description>把SSH登录通知发到Slack：用PAM和Slack的Incoming Webhook，在有人尝试SSH登录你的服务器时收到提醒，登录成功的通知也可以按需打开。</description>
      <content:encoded><![CDATA[
<h2 class="relative group">目的
    <div id="目的" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%9b%ae%e7%9a%84" aria-label="锚点">#</a>
    </span>
    
</h2>
<ul>
<li>SSH可以在有人尝试登录时执行命令。这篇文章介绍怎么接入Slack，同时控制PAM的执行顺序。</li>
</ul>

<h2 class="relative group">Slack API的Webhook
    <div id="slack-api的webhook" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#slack-api%e7%9a%84webhook" aria-label="锚点">#</a>
    </span>
    
</h2>
<ul>
<li>
<p>怎么创建应用，看<a href="https://api.slack.com/messaging/webhooks"  target="_blank" rel="noreferrer">这里</a>就行。</p>
</li>
<li>
<p>你需要先建一个Slack应用，启用Webhook，再创建一个Incoming Webhook，用来接收SSH发来的通知。</p>
</li>
</ul>

<h2 class="relative group">登录失败的通知脚本
    <div id="登录失败的通知脚本" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%99%bb%e5%bd%95%e5%a4%b1%e8%b4%a5%e7%9a%84%e9%80%9a%e7%9f%a5%e8%84%9a%e6%9c%ac" aria-label="锚点">#</a>
    </span>
    
</h2>
<ul>
<li>脚本放在哪里都行，我放在了<code>/var/opt/notify-attempt.sh</code>。</li>
</ul>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">#!/bin/bash
</span></span><span class="line"><span class="cl">if [ &#34;$PAM_TYPE&#34; != &#34;close_session&#34; ]; then
</span></span><span class="line"><span class="cl">        url=&#34;&lt;YOUR SLACK WEBHOOK&gt;&#34;
</span></span><span class="line"><span class="cl">        channel=&#34;#channel&#34;
</span></span><span class="line"><span class="cl">        host=&#34;$(hostname)&#34;
</span></span><span class="line"><span class="cl">        content=&#34;\&#34;attachments\&#34;: [ { \&#34;mrkdwn_in\&#34;: [\&#34;text\&#34;, \&#34;fallback\&#34;], \&#34;fallback\&#34;: \&#34;SSH login: $PAM_USER connected to \`$host\`\&#34;, \&#34;text\&#34;: \&#34;SSH login to \`$host\`\&#34;, \&#34;fields\&#34;: [ { \&#34;title\&#34;: \&#34;User\&#34;, \&#34;value\&#34;: \&#34;$PAM_USER\&#34;, \&#34;short\&#34;: true }, { \&#34;title\&#34;: \&#34;IP Address\&#34;, \&#34;value\&#34;: \&#34;$PAM_RHOST\&#34;, \&#34;short\&#34;: true } ], \&#34;color\&#34;: \&#34;#F35A00\&#34; } ]&#34;
</span></span><span class="line"><span class="cl">        curl -X POST --data-urlencode &#34;payload={\&#34;channel\&#34;: \&#34;$channel\&#34;, \&#34;mrkdwn\&#34;: true, \&#34;username\&#34;: \&#34;SSH Notifications\&#34;, $content, \&#34;icon_emoji\&#34;: \&#34;:inbox-tray:\&#34;}&#34; &#34;$url&#34; &amp;
</span></span><span class="line"><span class="cl">fi
</span></span><span class="line"><span class="cl">exit</span></span></code></pre></div></div>

<h3 class="relative group">其他SSH事件
    <div id="其他ssh事件" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%85%b6%e4%bb%96ssh%e4%ba%8b%e4%bb%b6" aria-label="锚点">#</a>
    </span>
    
</h3>
<ul>
<li>如果还想通知登录成功之类的事件，建议建两个文件。</li>
<li>每个文件里放好要发给Slack的JSON。</li>
<li>记得按事件改一下<code>fallback\&quot;: \&quot;SSH login: $PAM_USER connected to \</code>$host`&quot;`这一行。</li>
<li>OpenSSH怎么调用这些脚本，看下面的配置就明白了。</li>
</ul>

<h3 class="relative group">配置ssh
    <div id="配置ssh" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e9%85%8d%e7%bd%aessh" aria-label="锚点">#</a>
    </span>
    
</h3>
<p>登录成功的通知我注释掉了，想用的话取消注释，成功登录时也会发到Slack。
就是这一行：<code># auth  optional            pam_exec.so /var/opt/notify-login.sh</code></p>
<p>[success=2]的意思是：登录成功就往下跳两行，正好跳过了失败通知。</p>
<p>文件：<code>/etc/pam.d/common-auth</code></p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl"># /etc/pam.d/common-auth - authentication settings common to all services
</span></span><span class="line"><span class="cl">#
</span></span><span class="line"><span class="cl"># This file is included from other service-specific PAM config files,
</span></span><span class="line"><span class="cl"># and should contain a list of the authentication modules that define
</span></span><span class="line"><span class="cl"># the central authentication scheme for use on the system
</span></span><span class="line"><span class="cl"># (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
</span></span><span class="line"><span class="cl"># traditional Unix authentication mechanisms.
</span></span><span class="line"><span class="cl">#
</span></span><span class="line"><span class="cl"># As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
</span></span><span class="line"><span class="cl"># To take advantage of this, it is recommended that you configure any
</span></span><span class="line"><span class="cl"># local modules either before or after the default block, and use
</span></span><span class="line"><span class="cl"># pam-auth-update to manage selection of other modules. See
</span></span><span class="line"><span class="cl"># pam-auth-update(8) for details.
</span></span><span class="line"><span class="cl"># here are the per-package modules (the &#34;Primary&#34; block)
</span></span><span class="line"><span class="cl">auth  [success=2 default=ignore]   pam_unix.so nullok
</span></span><span class="line"><span class="cl">auth  optional            pam_exec.so /var/opt/notify-attempt.sh
</span></span><span class="line"><span class="cl"># here&#39;s the fallback if no module succeeds
</span></span><span class="line"><span class="cl">auth  requisite            pam_deny.so
</span></span><span class="line"><span class="cl"># prime the stack with a positive return value if there isn&#39;t one already;
</span></span><span class="line"><span class="cl"># this avoids us returning an error just because nothing sets a success code
</span></span><span class="line"><span class="cl"># since the modules above will each just jump around
</span></span><span class="line"><span class="cl"># For successful login, uncomment the below line, ensure the file exists.
</span></span><span class="line"><span class="cl"># auth  optional            pam_exec.so /var/opt/notify-login.sh
</span></span><span class="line"><span class="cl"># auth  required            pam_permit.so
</span></span><span class="line"><span class="cl"># and here are more per-package modules (the &#34;Additional&#34; block)
</span></span><span class="line"><span class="cl">auth  optional            pam_cap.so
</span></span><span class="line"><span class="cl"># end of pam-auth-update config</span></span></code></pre></div></div>

<h2 class="relative group">谢谢！
    <div id="谢谢" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%b0%a2%e8%b0%a2" aria-label="锚点">#</a>
    </span>
    
</h2>
<ul>
<li>有任何问题或想法，欢迎直接联系我</li>
</ul>
]]></content:encoded>
      <media:content url="https://jared.lynskey.co.nz/en/posts/2021/2021-12-14-ssh-log/featured.jpeg" medium="image" type="image/jpeg" />
    </item>
  </channel>
</rss>
