diff --git a/shell/aliyun.sh b/shell/aliyun.sh new file mode 100644 index 0000000..f98830e --- /dev/null +++ b/shell/aliyun.sh @@ -0,0 +1,26 @@ +if ps aux | grep -i '[a]liyun'; then + curl http://update.aegis.aliyun.com/download/uninstall.sh | bash + curl http://update.aegis.aliyun.com/download/quartz_uninstall.sh | bash + pkill aliyun-service + rm -rf /etc/init.d/agentwatch /usr/sbin/aliyun-service + rm -rf /usr/local/aegis* + systemctl stop aliyun.service + systemctl disable aliyun.service + service bcm-agent stop + yum remove bcm-agent -y + apt-get remove bcm-agent -y +elif ps aux | grep -i '[y]unjing'; then + /usr/local/qcloud/stargate/admin/uninstall.sh + /usr/local/qcloud/YunJing/uninst.sh + /usr/local/qcloud/monitor/barad/admin/uninstall.sh +fi +if [ -f /usr/local/cloudmonitor/wrapper/bin/cloudmonitor.sh ]; then + /usr/local/cloudmonitor/wrapper/bin/cloudmonitor.sh stop && /usr/local/cloudmonitor/wrapper/bin/cloudmonitor.sh remove && rm -rf /usr/local/cloudmonitor +else + export ARCH=amd64 + if [ -f /usr/local/cloudmonitor/CmsGoAgent.linux-${ARCH} ]; then + /usr/local/cloudmonitor/CmsGoAgent.linux-${ARCH} stop && /usr/local/cloudmonitor/CmsGoAgent.linux-${ARCH} uninstall && rm -rf /usr/local/cloudmonitor + else + echo "ali cloud monitor not running" + fi +fi \ No newline at end of file diff --git a/shell/init/init_centos.sh b/shell/init/init_centos.sh new file mode 100644 index 0000000..d95afc7 --- /dev/null +++ b/shell/init/init_centos.sh @@ -0,0 +1,457 @@ +#!/usr/bin/env bash + + +# Disable selinux +sed -i '/SELINUX/s/enforcing/disabled/' /etc/selinux/config +setenforce 0 + +# Disable swap +swapoff -a && sysctl -w vm.swappiness=0 +sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab + +# Disable firewalld +for target in firewalld python-firewall firewalld-filesystem iptables; do + systemctl stop $target &>/dev/null || true + systemctl disable $target &>/dev/null || true +done + +# repo +[ -f /etc/yum.repos.d/CentOS-Base.repo ] && sed -e 's!^#baseurl=!baseurl=!g' \ + -e 's!^mirrorlist=!#mirrorlist=!g' \ + -e 's!mirror.centos.org!mirrors.aliyun.com!g' \ + -i /etc/yum.repos.d/CentOS-Base.repo + +yum install -y epel-release + +[ -f /etc/yum.repos.d/epel.repo ] && sed -e 's!^mirrorlist=!#mirrorlist=!g' \ + -e 's!^metalink=!#metalink=!g' \ + -e 's!^#baseurl=!baseurl=!g' \ + -e 's!//download.*/pub!//mirrors.aliyun.com!g' \ + -e 's!http://mirrors\.aliyun!https://mirrors.aliyun!g' \ + -i /etc/yum.repos.d/epel.repo + +# Change limits +[ ! -f /etc/security/limits.conf_bak ] && cp /etc/security/limits.conf{,_bak} +cat << EOF >> /etc/security/limits.conf +## Kainstall managed start +root soft nofile 655360 +root hard nofile 655360 +root soft nproc 655360 +root hard nproc 655360 +root soft core unlimited +root hard core unlimited +* soft nofile 655360 +* hard nofile 655360 +* soft nproc 655360 +* hard nproc 655360 +* soft core unlimited +* hard core unlimited +## Kainstall managed end +EOF + +[ -f /etc/security/limits.d/20-nproc.conf ] && sed -i 's#4096#655360#g' /etc/security/limits.d/20-nproc.conf +cat << EOF >> /etc/systemd/system.conf +## Kainstall managed start +DefaultLimitCORE=infinity +DefaultLimitNOFILE=655360 +DefaultLimitNPROC=655360 +DefaultTasksMax=75% +## Kainstall managed end +EOF + +# Change sysctl +cat << EOF > /etc/sysctl.d/99-kube.conf +# https://www.kernel.org/doc/Documentation/sysctl/ +############################################################################################# +# 调整虚拟内存 +############################################################################################# +# Default: 30 +# 0 - 任何情况下都不使用swap。 +# 1 - 除非内存不足(OOM),否则不使用swap。 +vm.swappiness = 0 +# 内存分配策略 +#0 - 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。 +#1 - 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。 +#2 - 表示内核允许分配超过所有物理内存和交换空间总和的内存 +vm.overcommit_memory=1 +# OOM时处理 +# 1关闭,等于0时,表示当内存耗尽时,内核会触发OOM killer杀掉最耗内存的进程。 +vm.panic_on_oom=0 +# vm.dirty_background_ratio 用于调整内核如何处理必须刷新到磁盘的脏页。 +# Default value is 10. +# 该值是系统内存总量的百分比,在许多情况下将此值设置为5是合适的。 +# 此设置不应设置为零。 +vm.dirty_background_ratio = 5 +# 内核强制同步操作将其刷新到磁盘之前允许的脏页总数 +# 也可以通过更改 vm.dirty_ratio 的值(将其增加到默认值30以上(也占系统内存的百分比))来增加 +# 推荐 vm.dirty_ratio 的值在60到80之间。 +vm.dirty_ratio = 60 +# vm.max_map_count 计算当前的内存映射文件数。 +# mmap 限制(vm.max_map_count)的最小值是打开文件的ulimit数量(cat /proc/sys/fs/file-max)。 +# 每128KB系统内存 map_count应该大约为1。 因此,在32GB系统上,max_map_count为262144。 +# Default: 65530 +vm.max_map_count = 2097152 +############################################################################################# +# 调整文件 +############################################################################################# +fs.may_detach_mounts = 1 +# 增加文件句柄和inode缓存的大小,并限制核心转储。 +fs.file-max = 2097152 +fs.nr_open = 2097152 +fs.suid_dumpable = 0 +# 文件监控 +fs.inotify.max_user_instances=8192 +fs.inotify.max_user_watches=524288 +fs.inotify.max_queued_events=16384 +############################################################################################# +# 调整网络设置 +############################################################################################# +# 为每个套接字的发送和接收缓冲区分配的默认内存量。 +net.core.wmem_default = 25165824 +net.core.rmem_default = 25165824 +# 为每个套接字的发送和接收缓冲区分配的最大内存量。 +net.core.wmem_max = 25165824 +net.core.rmem_max = 25165824 +# 除了套接字设置外,发送和接收缓冲区的大小 +# 必须使用net.ipv4.tcp_wmem和net.ipv4.tcp_rmem参数分别设置TCP套接字。 +# 使用三个以空格分隔的整数设置这些整数,分别指定最小,默认和最大大小。 +# 最大大小不能大于使用net.core.wmem_max和net.core.rmem_max为所有套接字指定的值。 +# 合理的设置是最小4KiB,默认64KiB和最大2MiB缓冲区。 +net.ipv4.tcp_wmem = 20480 12582912 25165824 +net.ipv4.tcp_rmem = 20480 12582912 25165824 +# 增加最大可分配的总缓冲区空间 +# 以页为单位(4096字节)进行度量 +net.ipv4.tcp_mem = 65536 25165824 262144 +net.ipv4.udp_mem = 65536 25165824 262144 +# 为每个套接字的发送和接收缓冲区分配的最小内存量。 +net.ipv4.udp_wmem_min = 16384 +net.ipv4.udp_rmem_min = 16384 +# 启用TCP窗口缩放,客户端可以更有效地传输数据,并允许在代理方缓冲该数据。 +net.ipv4.tcp_window_scaling = 1 +# 提高同时接受连接数。 +net.ipv4.tcp_max_syn_backlog = 10240 +# 将net.core.netdev_max_backlog的值增加到大于默认值1000 +# 可以帮助突发网络流量,特别是在使用数千兆位网络连接速度时, +# 通过允许更多的数据包排队等待内核处理它们。 +net.core.netdev_max_backlog = 65536 +# 增加选项内存缓冲区的最大数量 +net.core.optmem_max = 25165824 +# 被动TCP连接的SYNACK次数。 +net.ipv4.tcp_synack_retries = 2 +# 允许的本地端口范围。 +net.ipv4.ip_local_port_range = 2048 65535 +# 防止TCP时间等待 +# Default: net.ipv4.tcp_rfc1337 = 0 +net.ipv4.tcp_rfc1337 = 1 +# 减少tcp_fin_timeout连接的时间默认值 +net.ipv4.tcp_fin_timeout = 15 +# 积压套接字的最大数量。 +# Default is 128. +net.core.somaxconn = 32768 +# 打开syncookies以进行SYN洪水攻击保护。 +net.ipv4.tcp_syncookies = 1 +# 避免Smurf攻击 +# 发送伪装的ICMP数据包,目的地址设为某个网络的广播地址,源地址设为要攻击的目的主机, +# 使所有收到此ICMP数据包的主机都将对目的主机发出一个回应,使被攻击主机在某一段时间内收到成千上万的数据包 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +# 为icmp错误消息打开保护 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +# 启用自动缩放窗口。 +# 如果延迟证明合理,这将允许TCP缓冲区超过其通常的最大值64K。 +net.ipv4.tcp_window_scaling = 1 +# 打开并记录欺骗,源路由和重定向数据包 +net.ipv4.conf.all.log_martians = 1 +net.ipv4.conf.default.log_martians = 1 +# 告诉内核有多少个未附加的TCP套接字维护用户文件句柄。 万一超过这个数字, +# 孤立的连接会立即重置,并显示警告。 +# Default: net.ipv4.tcp_max_orphans = 65536 +net.ipv4.tcp_max_orphans = 65536 +# 不要在关闭连接时缓存指标 +net.ipv4.tcp_no_metrics_save = 1 +# 启用RFC1323中定义的时间戳记: +# Default: net.ipv4.tcp_timestamps = 1 +net.ipv4.tcp_timestamps = 1 +# 启用选择确认。 +# Default: net.ipv4.tcp_sack = 1 +net.ipv4.tcp_sack = 1 +# 增加 tcp-time-wait 存储桶池大小,以防止简单的DOS攻击。 +# net.ipv4.tcp_tw_recycle 已从Linux 4.12中删除。请改用net.ipv4.tcp_tw_reuse。 +net.ipv4.tcp_max_tw_buckets = 14400 +net.ipv4.tcp_tw_reuse = 1 +# accept_source_route 选项使网络接口接受设置了严格源路由(SSR)或松散源路由(LSR)选项的数据包。 +# 以下设置将丢弃设置了SSR或LSR选项的数据包。 +net.ipv4.conf.all.accept_source_route = 0 +net.ipv4.conf.default.accept_source_route = 0 +# 打开反向路径过滤 +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +# 禁用ICMP重定向接受 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.secure_redirects = 0 +net.ipv4.conf.default.secure_redirects = 0 +# 禁止发送所有IPv4 ICMP重定向数据包。 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +# 开启IP转发. +net.ipv4.ip_forward = 1 +# 禁止IPv6 +net.ipv6.conf.lo.disable_ipv6=1 +net.ipv6.conf.all.disable_ipv6 = 1 +net.ipv6.conf.default.disable_ipv6 = 1 +# 要求iptables不对bridge的数据进行处理 +net.bridge.bridge-nf-call-ip6tables = 1 +net.bridge.bridge-nf-call-iptables = 1 +net.bridge.bridge-nf-call-arptables = 1 +# arp缓存 +# 存在于 ARP 高速缓存中的最少层数,如果少于这个数,垃圾收集器将不会运行。缺省值是 128 +net.ipv4.neigh.default.gc_thresh1=2048 +# 保存在 ARP 高速缓存中的最多的记录软限制。垃圾收集器在开始收集前,允许记录数超过这个数字 5 秒。缺省值是 512 +net.ipv4.neigh.default.gc_thresh2=4096 +# 保存在 ARP 高速缓存中的最多记录的硬限制,一旦高速缓存中的数目高于此,垃圾收集器将马上运行。缺省值是 1024 +net.ipv4.neigh.default.gc_thresh3=8192 +# 持久连接 +net.ipv4.tcp_keepalive_time = 600 +net.ipv4.tcp_keepalive_intvl = 30 +net.ipv4.tcp_keepalive_probes = 10 +# conntrack表 +net.nf_conntrack_max=1048576 +net.netfilter.nf_conntrack_max=1048576 +net.netfilter.nf_conntrack_buckets=262144 +net.netfilter.nf_conntrack_tcp_timeout_fin_wait=30 +net.netfilter.nf_conntrack_tcp_timeout_time_wait=30 +net.netfilter.nf_conntrack_tcp_timeout_close_wait=15 +net.netfilter.nf_conntrack_tcp_timeout_established=300 +############################################################################################# +# 调整内核参数 +############################################################################################# +# 地址空间布局随机化(ASLR)是一种用于操作系统的内存保护过程,可防止缓冲区溢出攻击。 +# 这有助于确保与系统上正在运行的进程相关联的内存地址不可预测, +# 因此,与这些流程相关的缺陷或漏洞将更加难以利用。 +# Accepted values: 0 = 关闭, 1 = 保守随机化, 2 = 完全随机化 +kernel.randomize_va_space = 2 +# 调高 PID 数量 +kernel.pid_max = 65536 +kernel.threads-max=30938 +# coredump +kernel.core_pattern=core +# 决定了检测到soft lockup时是否自动panic,缺省值是0 +kernel.softlockup_all_cpu_backtrace=1 +kernel.softlockup_panic=1 +EOF + + # history + cat << EOF >> /etc/bashrc +## Kainstall managed start +# history actions record,include action time, user, login ip +HISTFILESIZE=5000 +HISTSIZE=5000 +USER_IP=\$(who -u am i 2>/dev/null | awk '{print \$NF}' | sed -e 's/[()]//g') +if [ -z \$USER_IP ] +then + USER_IP=\$(hostname -i) +fi +HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S \$USER_IP:\$(whoami) " +export HISTFILESIZE HISTSIZE HISTTIMEFORMAT +# PS1 +PS1='\[\033[0m\]\[\033[1;36m\][\u\[\033[0m\]@\[\033[1;32m\]\h\[\033[0m\] \[\033[1;31m\]\w\[\033[0m\]\[\033[1;36m\]]\[\033[33;1m\]\\$ \[\033[0m\]' +## Kainstall managed end +EOF + + # journal + mkdir -p /var/log/journal /etc/systemd/journald.conf.d + cat << EOF > /etc/systemd/journald.conf.d/99-prophet.conf +[Journal] +# 持久化保存到磁盘 +Storage=persistent +# 压缩历史日志 +Compress=yes +SyncIntervalSec=5m +RateLimitInterval=30s +RateLimitBurst=1000 +# 最大占用空间 10G +SystemMaxUse=10G +# 单日志文件最大 200M +SystemMaxFileSize=200M +# 日志保存时间 3 周 +MaxRetentionSec=3week +# 不将日志转发到 syslog +ForwardToSyslog=no +EOF + +# motd +cat << EOF > /etc/profile.d/zz-ssh-login-info.sh +#!/bin/sh +# +# @Time : 2020-02-04 +# @Author : lework +# @Desc : ssh login banner +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +shopt -q login_shell && : || return 0 +# os +upSeconds="\$(cut -d. -f1 /proc/uptime)" +secs=\$((\${upSeconds}%60)) +mins=\$((\${upSeconds}/60%60)) +hours=\$((\${upSeconds}/3600%24)) +days=\$((\${upSeconds}/86400)) +UPTIME_INFO=\$(printf "%d days, %02dh %02dm %02ds" "\$days" "\$hours" "\$mins" "\$secs") +if [ -f /etc/redhat-release ] ; then + PRETTY_NAME=\$(< /etc/redhat-release) +elif [ -f /etc/debian_version ]; then + DIST_VER=\$(/dev/null | tail -1) +disktotal=\$(awk '{print \$2}' <<< "\${totaldisk}") +diskused=\$(awk '{print \$3}' <<< "\${totaldisk}") +diskusedper=\$(awk '{print \$5}' <<< "\${totaldisk}") +DISK_INFO="\033[0;33m\${diskused}\033[0m of \033[1;34m\${disktotal}\033[0m disk space used (\033[0;33m\${diskusedper}\033[0m)" +# cpu +cpu=\$(awk -F':' '/^model name/ {print \$2}' /proc/cpuinfo | uniq | sed -e 's/^[ \t]*//') +cpun=\$(grep -c '^processor' /proc/cpuinfo) +cpuc=\$(grep '^cpu cores' /proc/cpuinfo | tail -1 | awk '{print \$4}') +cpup=\$(grep '^physical id' /proc/cpuinfo | wc -l) +CPU_INFO="\${cpu} \${cpup}P \${cpuc}C \${cpun}L" +# get the load averages +read one five fifteen rest < /proc/loadavg +LOADAVG_INFO="\033[0;33m\${one}\033[0m / \${five} / \${fifteen} with \033[1;34m\$(( cpun*cpuc ))\033[0m core(s) at \033[1;34m\$(grep '^cpu MHz' /proc/cpuinfo | tail -1 | awk '{print \$4}')\033 MHz" +# mem +MEM_INFO="\$(cat /proc/meminfo | awk '/MemTotal:/{total=\$2/1024/1024;next} /MemAvailable:/{use=total-\$2/1024/1024; printf("\033[0;33m%.2fGiB\033[0m of \033[1;34m%.2fGiB\033[0m RAM used (\033[0;33m%.2f%%\033[0m)",use,total,(use/total)*100);}')" +# network +# extranet_ip=" and \$(curl -s ip.cip.cc)" +IP_INFO="\$(ip a | grep glo | awk '{print \$2}' | head -1 | cut -f1 -d/)\${extranet_ip:-}" +# Container info +CONTAINER_INFO="\$(sudo /usr/bin/crictl ps -a -o yaml 2> /dev/null | awk '/^ state: /{gsub("CONTAINER_", "", \$NF) ++S[\$NF]}END{for(m in S) printf "%s%s:%s ",substr(m,1,1),tolower(substr(m,2)),S[m]}')Images:\$(sudo /usr/bin/crictl images -q 2> /dev/null | wc -l)" +# info +echo -e " + Information as of: \033[1;34m\$(date +"%Y-%m-%d %T")\033[0m + + \033[0;1;31mProduct\033[0m............: \${MODEL_INFO} + \033[0;1;31mOS\033[0m.................: \${PRETTY_NAME} + \033[0;1;31mKernel\033[0m.............: \${KERNEL} + \033[0;1;31mCPU\033[0m................: \${CPU_INFO} + \033[0;1;31mHostname\033[0m...........: \033[1;34m\$(hostname)\033[0m + \033[0;1;31mIP Addresses\033[0m.......: \033[1;34m\${IP_INFO}\033[0m + \033[0;1;31mUptime\033[0m.............: \033[0;33m\${UPTIME_INFO}\033[0m + \033[0;1;31mMemory\033[0m.............: \${MEM_INFO} + \033[0;1;31mLoad Averages\033[0m......: \${LOADAVG_INFO} + \033[0;1;31mDisk Usage\033[0m.........: \${DISK_INFO} + \033[0;1;31mUsers online\033[0m.......: \033[1;34m\${USER_NUM}\033[0m + \033[0;1;31mRunning Processes\033[0m..: \033[1;34m\${RUNNING}\033[0m + \033[0;1;31mContainer Info\033[0m.....: \${CONTAINER_INFO} +" +EOF + +chmod +x /etc/profile.d/zz-ssh-login-info.sh +echo 'ALL ALL=(ALL) NOPASSWD:/usr/bin/crictl' > /etc/sudoers.d/crictl + +# time sync +ntpd --help >/dev/null 2>&1 && yum remove -y ntp +yum install -y chrony +[ ! -f /etc/chrony.conf_bak ] && cp /etc/chrony.conf{,_bak} #备份默认配置 +cat << EOF > /etc/chrony.conf +server ntp.aliyun.com iburst +server cn.ntp.org.cn iburst +server ntp.shu.edu.cn iburst +server 0.cn.pool.ntp.org iburst +server 1.cn.pool.ntp.org iburst +server 2.cn.pool.ntp.org iburst +server 3.cn.pool.ntp.org iburst +driftfile /var/lib/chrony/drift +makestep 1.0 3 +logdir /var/log/chrony +EOF + +timedatectl set-timezone Asia/Shanghai +chronyd -q -t 1 'server cn.pool.ntp.org iburst maxsamples 1' +systemctl enable chronyd +systemctl start chronyd +chronyc sources -v +chronyc sourcestats +hwclock --systohc + +# package +yum install -y curl wget + +# ipvs +yum install -y ipvsadm ipset sysstat conntrack libseccomp +module=( +ip_vs +ip_vs_rr +ip_vs_wrr +ip_vs_sh +overlay +nf_conntrack +br_netfilter +) +[ -f /etc/modules-load.d/ipvs.conf ] && cp -f /etc/modules-load.d/ipvs.conf{,_bak} +for kernel_module in "${module[@]}";do + /sbin/modinfo -F filename "$kernel_module" |& grep -qv ERROR && echo "$kernel_module" >> /etc/modules-load.d/ipvs.conf +done +systemctl restart systemd-modules-load +systemctl enable systemd-modules-load +sysctl --system + +# audit +yum install -y audit audit-libs +cat << EOF >> /etc/audit/rules.d/audit.rules +## Kainstall managed start +# Ignore errors +-i +# SYSCALL +-a always,exit -F arch=b64 -S kill,tkill,tgkill -F a1=9 -F key=trace_kill_9 +-a always,exit -F arch=b64 -S kill,tkill,tgkill -F a1=15 -F key=trace_kill_15 +# docker +-w /usr/bin/dockerd -k docker +-w /var/lib/docker -k docker +-w /etc/docker -k docker +-w /usr/lib/systemd/system/docker.service -k docker +-w /etc/systemd/system/docker.service -k docker +-w /usr/lib/systemd/system/docker.socket -k docker +-w /etc/default/docker -k docker +-w /etc/sysconfig/docker -k docker +-w /etc/docker/daemon.json -k docker +# containerd +-w /usr/bin/containerd -k containerd +-w /var/lib/containerd -k containerd +-w /usr/lib/systemd/system/containerd.service -k containerd +-w /etc/containerd/config.toml -k containerd +# cri-o +-w /usr/bin/crio -k cri-o +-w /etc/crio -k cri-o +# runc +-w /usr/bin/runc -k runc +# kube +-w /usr/bin/kubeadm -k kubeadm +-w /usr/bin/kubelet -k kubelet +-w /usr/bin/kubectl -k kubectl +-w /var/lib/kubelet -k kubelet +-w /etc/kubernetes -k kubernetes +## Kainstall managed end +EOF +chmod 600 /etc/audit/rules.d/audit.rules +sed -i 's#max_log_file =.*#max_log_file = 80#g' /etc/audit/auditd.conf +if [ -f /usr/libexec/initscripts/legacy-actions/auditd/restart ]; then + /usr/libexec/initscripts/legacy-actions/auditd/restart +else + systemctl stop auditd && systemctl start auditd +fi +systemctl enable auditd \ No newline at end of file diff --git a/shell/k8s/diagnose_k8s.sh b/shell/k8s/diagnose_k8s.sh new file mode 100644 index 0000000..11773f5 --- /dev/null +++ b/shell/k8s/diagnose_k8s.sh @@ -0,0 +1,338 @@ +#!/usr/bin/env bash + +set -x +current_dir=$(pwd) +timestamp=$(date +%s) +diagnose_dir=/tmp/diagnose_${timestamp} +mkdir -p $diagnose_dir +is_ps_hang=false + +run() { + echo + echo "-----------------run $@------------------" + timeout 10s $@ + if [ "$?" != "0" ]; then + echo "failed to collect info: $@" + fi + echo "------------End of ${1}----------------" +} + +os_env() +{ + grep -q "Ubuntu" /etc/os-release && export OS="Ubuntu" && return + grep -q "SUSE" /etc/os-release && export OS="SUSE" && return + grep -q "Red Hat" /etc/os-release && export OS="RedHat" && return + grep -q "CentOS Linux" /etc/os-release && export OS="CentOS" && return + grep -q "Kylin Linux" /etc/os-release && export OS="CentOS" && return + grep -q "Aliyun Linux" /etc/os-release && export OS="AliyunOS" && return + grep -q "Alibaba Group Enterprise Linux" /etc/os-release && export OS="AliOS" && return + + echo "unknown os... exit." + exit 1 +} + +dist() { + cat /etc/issue* +} + +command_exists() { + command -v "$@" > /dev/null 2>&1 +} + +# Service status +service_status() { + run service firewalld status | tee $diagnose_dir/service_status + run service ntpd status | tee $diagnose_dir/service_status + run service chronyd status | tee $diagnose_dir/service_status +} + + +#system info + +system_info() { + # mkdir -p ${diagnose_dir}/system_info + run uname -a | tee -a ${diagnose_dir}/system_info + run uname -r | tee -a ${diagnose_dir}/system_info + run dist | tee -a ${diagnose_dir}/system_info + if command_exists lsb_release; then + run lsb_release | tee -a ${diagnose_dir}/system_info + fi + run ulimit -a | tee -a ${diagnose_dir}/system_info + run sysctl -a | tee -a ${diagnose_dir}/system_info +} + +#network +network_info() { + # mkdir -p ${diagnose_dir}/network_info + #run ifconfig + run ip --details ad show | tee -a ${diagnose_dir}/network_info + run ip --details link show | tee -a ${diagnose_dir}/network_info + run ip route show | tee -a ${diagnose_dir}/network_info + run iptables-save | tee -a ${diagnose_dir}/network_info + netstat -nt | tee -a ${diagnose_dir}/network_info + netstat -nu | tee -a ${diagnose_dir}/network_info + netstat -ln | tee -a ${diagnose_dir}/network_info +} + + +# check ps -ef command is hung +check_ps_hang() { + echo "check if ps -ef command hang" | tee -a ${diagnose_dir}/ps_command_status + checkD=$(timeout -s 9 2 ps -ef) + if [ "$?" != "0" ]; then + echo "ps -ef command is hung" | tee -a ${diagnose_dir}/ps_command_status + is_ps_hang=true + echo "start to check which process lead to ps -ef command hang" | tee -a ${diagnose_dir}/ps_command_status + for f in `find /proc/*/task -name status` + do + checkD=$(cat $f|grep "State.*D") + if [ "$?" == "0" ]; then + cmdline=$(echo ${f%%status}"cmdline") + pid=$(echo ${f%%status}"") + stack=$(echo ${f%%status}"stack") + timeout -s 9 2 cat $cmdline + if [ "$?" != "0" ]; then + echo "process $pid is in State D and lead to ps -ef process hang,stack info:" | tee -a ${diagnose_dir}/ps_command_status + cat $stack | tee -a ${diagnose_dir}/ps_command_status + fi + fi + done + echo "finish to check which process lead to ps -ef command hang" | tee -a ${diagnose_dir}/ps_command_status + else + echo "ps -ef command works fine" | tee -a ${diagnose_dir}/ps_command_status + fi +} + + +#system status +system_status() { + #mkdir -p ${diagnose_dir}/system_status + run uptime | tee -a ${diagnose_dir}/system_status + run top -b -n 1 | tee -a ${diagnose_dir}/system_status + if [ "$is_ps_hang" == "false" ]; then + run ps -ef | tee -a ${diagnose_dir}/system_status + else + echo "ps -ef command hang, skip [ps -ef] check" | tee -a ${diagnose_dir}/system_status + fi + run netstat -nt | tee -a ${diagnose_dir}/system_status + run netstat -nu | tee -a ${diagnose_dir}/system_status + run netstat -ln | tee -a ${diagnose_dir}/system_status + + run df -h | tee -a ${diagnose_dir}/system_status + + run cat /proc/mounts | tee -a ${diagnose_dir}/system_status + + if [ "$is_ps_hang" == "false" ]; then + run pstree -al | tee -a ${diagnose_dir}/system_status + else + echo "ps -ef command hang, skip [pstree -al] check" | tee -a ${diagnose_dir}/system_status + fi + + run lsof | tee -a ${diagnose_dir}/system_status + + ( + cd /proc + find -maxdepth 1 -type d -name '[0-9]*' \ + -exec bash -c "ls {}/fd/ | wc -l | tr '\n' ' '" \; \ + -printf "fds (PID = %P), command: " \ + -exec bash -c "tr '\0' ' ' < {}/cmdline" \; \ + -exec echo \; | sort -rn | head | tee -a ${diagnose_dir}/system_status + ) +} + + +daemon_status() { + run systemctl status docker -l | tee -a ${diagnose_dir}/docker_status + run systemctl status containerd -l | tee -a ${diagnose_dir}/containerd_status + run systemctl status container-storaged -l | tee -a ${diagnose_dir}/container-storaged_status + run systemctl status kubelet -l | tee -a ${diagnose_dir}/kubelet_status +} + +docker_status() { + #mkdir -p ${diagnose_dir}/docker_status + echo "check dockerd process" + if [ "$is_ps_hang" == "false" ]; then + run ps -ef|grep -E 'dockerd|docker daemon'|grep -v grep| tee -a ${diagnose_dir}/docker_status + else + echo "ps -ef command hang, skip [ps -ef|grep -E 'dockerd|docker daemon'] check" | tee -a ${diagnose_dir}/docker_status + fi + + #docker info + run docker info | tee -a ${diagnose_dir}/docker_status + run docker version | tee -a ${diagnose_dir}/docker_status + sudo kill -SIGUSR1 $(cat /var/run/docker.pid) + cp /var/run/docker/libcontainerd/containerd/events.log ${diagnose_dir}/containerd_events.log + sleep 10 + cp /var/run/docker/*.log ${diagnose_dir} + +} + +showlog() { + local file=$1 + if [ -f "$file" ]; then + tail -n 200 $file + fi +} + +#collect log +common_logs() { + log_tail_lines=10000 + mkdir -p ${diagnose_dir}/logs + run dmesg -T | tail -n ${log_tail_lines} | tee ${diagnose_dir}/logs/dmesg.log + tail -c 500M /var/log/messages &> ${diagnose_dir}/logs/messages + pidof systemd && journalctl -n ${log_tail_lines} -u docker.service &> ${diagnose_dir}/logs/docker.log || tail -n ${log_tail_lines} /var/log/upstart/docker.log &> ${diagnose_dir}/logs/docker.log +} + +archive() { + tar -zcvf ${current_dir}/diagnose_${timestamp}.tar.gz ${diagnose_dir} + echo "please get diagnose_${timestamp}.tar.gz for diagnostics" +} + +varlogmessage(){ + grep cloud-init /var/log/messages > $diagnose_dir/varlogmessage.log +} + +cluster_dump(){ + kubectl cluster-info dump > $diagnose_dir/cluster_dump.log +} + +events(){ + kubectl get events > $diagnose_dir/events.log +} + +core_component() { + local comp="$1" + local label="$2" + mkdir -p $diagnose_dir/cs/$comp/ + local pods=`kubectl get -n kube-system po -l $label=$comp | awk '{print $1}'|grep -v NAME` + for po in ${pods} + do + kubectl logs -n kube-system ${po} &> $diagnose_dir/cs/${comp}/${po}.log + done +} + +etcd() { + journalctl -u etcd -xe &> $diagnose_dir/cs/etcd.log +} + +storageplugins() { + mkdir -p ${diagnose_dir}/storage/ + cp /var/log/alicloud/* ${diagnose_dir}/storage/ +} + +sandbox_runtime_status() { + if [[ ! -z $(pidof dockerd) || -z $(pidof containerd) ]]; then + return 0 + fi + wget http://aliacs-k8s-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/public/diagnose/sandbox-runtime-status.tgz -q -O ${diagnose_dir}/sandbox-runtime-status.tgz + tar -xzvf ${diagnose_dir}/sandbox-runtime-status.tgz -C ${diagnose_dir} + pushd ${diagnose_dir}/sandbox-runtime-status + bash script_collect.sh >> $diagnose_dir/sandbox_runtime.status + popd +} + +upload_oss() { + if [[ "$UPLOAD_OSS" == "" ]]; then + return 0 + fi + + bucket_path=${UPLOAD_OSS} + diagnose_file=diagnose_${timestamp}.tar.gz + + if ! command_exists ossutil; then + curl -o /usr/local/bin/ossutil http://gosspublic.alicdn.com/ossutil/1.6.10/ossutil64 + chmod u+x /usr/local/bin/ossutil + fi + + + region=$(curl http://100.100.100.200/latest/meta-data/region-id) + endpoint="oss-$region.aliyuncs.com" + if [[ "$ACCESS_KEY_ID" == "" ]]; then + roleName=$(curl 100.100.100.200/latest/meta-data/ram/security-credentials/) + echo " +[Credentials] + language = CH + endpoint = $endpoint +[AkService] + ecsAk=http://100.100.100.200/latest/meta-data/Ram/security-credentials/$roleName" > ./config + else + echo " +[Credentials] + language = CH + endpoint = $endpoint + accessKeyID = $ACCESS_KEY_ID + accessKeySecret = $ACCESS_KEY_SECRET +" > ./config + fi + bucket_name=${bucket_path%%/*} + oss_endpoint=$(ossutil stat oss://$bucket_name --config-file ./config | grep ExtranetEndpoint | awk '{print $3}') + if [[ "$oss_endpoint" != "" ]]; then + endpoint=$oss_endpoint + fi + ossutil cp ./${diagnose_file} oss://$bucket_path/$diagnose_file --config-file ./config --endpoint $endpoint + + if [[ "$OSS_PUBLIC_LINK" != "" ]]; then + ossutil sign --timeout 7200 oss://$bucket_path/$diagnose_file --config-file ./config --endpoint $endpoint + fi +} + +parse_args() { + while + [[ $# -gt 0 ]] + do + key="$1" + + case $key in + --oss) + export UPLOAD_OSS=$2 + shift + ;; + --oss-public-link) + export OSS_PUBLIC_LINK="true" + ;; + --access-key-id) + export ACCESS_KEY_ID=$2 + shift + ;; + --access-key-secret) + export ACCESS_KEY_SECRET=$2 + shift + ;; + *) + echo "unknown option [$key]" + ;; + esac + shift + done +} + +pd_collect() { + os_env + system_info + service_status + network_info + check_ps_hang + system_status + docker_status + sandbox_runtime_status + common_logs + + varlogmessage + core_component "cloud-controller-manager" "app" + core_component "kube-apiserver" "component" + core_component "kube-controller-manager" "component" + core_component "kube-scheduler" "component" + events + storageplugins + etcd + cluster_dump + archive +} + +parse_args "$@" + +pd_collect + +upload_oss + +echo "请上传 diagnose_${timestamp}.tar.gz" diff --git a/shell/library.sh b/shell/library.sh index 728b9ed..b714f65 100644 --- a/shell/library.sh +++ b/shell/library.sh @@ -803,4 +803,4 @@ function utils::quote() { else echo "$@" fi -} +} \ No newline at end of file diff --git a/shell/poorjson.sh b/shell/poorjson.sh new file mode 100644 index 0000000..189fc82 --- /dev/null +++ b/shell/poorjson.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# A POSIX compatible JSON parser within 60 lines of code (without comments) +# Usage example: +# $ echo '{ "key1" : { "key2": {}, "key3": [null, true, false, "value"]}}' | ./poorjson.sh '"key1"' '"key3"' 3 +# $ "value" +# shellcheck disable=SC2015 + +__JNUM='\(-\?\(0\|[1-9][0-9]*\)\(\.[0-9]\+\)\?\([eE][+-]\?[0-9]\+\)\?\)' +__JSTR='\("\([^[:cntrl:]"]\|\\["\\\/bfnrt]\|u[0-9]{4}\)*"\)' +_TOKEN="" _TMP="" __JTOK="$__JSTR\|$__JNUM\|true\|false\|null\|[][}{,:]" + +_is_match() { [ "$1" = "$2" ] || [ "$1" = \* ] || [ "$1" = . ]; } +_eof_error() { echo "Unexpected EOF after \"$_TOKEN\""; exit 1; } +_token_error() { echo "Unexpected token \"$_TOKEN\""; exit 1; } +_jread() { + read -r _TOKEN || _eof_error + [ "$1" = . ] && echo "$_TOKEN" +} + +_jarr() { + if _is_match "$1" 0; then _jval "$@"; else _jval; fi || { + [ "$_TOKEN" = ']' ] && return || _token_error + } + while :; do + _jread "$1"; + case $_TOKEN in "]") return 0;; + ",") [ "$1" -ge 0 ] 2>/dev/null && _TMP=$(( $1 - 1)) && shift && set -- "$_TMP" "$@";; + *) _token_error;; + esac + if _is_match "$1" 0; then _jval "$@"; else _jval; fi || _token_error + done +} + +_jobj() { + _jread "$1"; [ "$_TOKEN" = "}" ] && return 0 + while :; do + _TMP=$_TOKEN + case $_TMP in '"'*'"') + _jread "$1" + [ "$_TOKEN" = ":" ] || _token_error + if _is_match "$1" "$_TMP"; then _jval "$@"; else _jval; fi || _token_error + _jread "$1" + [ "$_TOKEN" = "}" ] && return 0 + [ "$_TOKEN" != "," ] && _token_error + _jread "$1" + continue + ;; + esac + _token_error + done +} + +_jval() { + [ "$#" -eq 0 ] || [ "$*" = . ] || shift + _jread "$1" + case $_TOKEN in '{') _jobj "$@";; + "[") _jarr "$@";; + true|false|null|-*|[0-9]*|'"'*'"') [ "$1" = \* ] && echo "$_TOKEN"; :;; + *) return 1;; + esac +} + +sed -e "s/\($__JTOK\)/\n\1\n/g" | sed -e "/^\s*$/d;/$__JTOK/!{q255};" | { _jval "" "$@" . && ! read -r; } || { + echo "JSON string invalid." + exit 1 +} diff --git a/shell/test/ssl-cert-check.sh b/shell/test/ssl-cert-check.sh new file mode 100644 index 0000000..da4ec95 --- /dev/null +++ b/shell/test/ssl-cert-check.sh @@ -0,0 +1,955 @@ +#!/usr/bin/env bash +PROGRAMVERSION=4.14 +# +# Program: SSL Certificate Check +# +# Source code home: https://github.com/Matty9191/ssl-cert-check +# +# Documentation: http://prefetch.net/articles/checkcertificate.html +# +# Author: Matty < matty at prefetch dot net > +# +# Last Updated: 11-12-2020 +# +# Revision History: +# +# Version 4.14 +# - Fixed HOST / PORT discovery @mhow2 +# +# Version 4.13 +# - Reverted the file checking logic which breaks $RETCODE +# +# Version 4.12 +# - Fixed various logic errors and typos -- Daniel Lewart +# +# Version 4.10 +# - Replace tabs with spaces +# - More shllcheck cleanup work +# - Remove unused DEBUG variable +# - Fixed an innocuous whitespace bug in TLSFLAG variable creation +# - Set the default TLS version to 1.1 (can be overridden with -v) +# - Switched openssl CLI options to use an array. The reasons why +# are documented here: http://mywiki.wooledge.org/BashFAQ/050 +# +# Version 4.9 +# - Add a signal handler to call the cleanup funtion +# if the script doesn't exit() cleanly -- Timothe Litt +# +# Version 4.8 +# - More mail client fixes +# +# Version 4.7 +# - Revert SENDER to "" +# - More shellcheck cleanup +# +# Version 4.6 +# - Fixed programming logic error +# +# Version 4.5 +# - Re-work mailx support for FreeBSD +# - More shellcheck fixes +# +# Version 4.4 +# - Use command -v instead of which utility to satisfy shellcheck. +# - Fix unquoted MAIL and MAILMODE variables in help output +# - More shellcheck fixes +# +# Version 4.3 +# - Fixed a typo in the program version +# +# Version 4.2 +# - Change CERTDAYS to CERTDIFF in the e-mail subject. +# +# Version 4.1 +# - Fix usage output +# +# Version 4.0 +# - Updated the script syntax to align with UNIX shell programming +# - Check for DNS resolution failures +# - First round of updates to make shellcheck happy +# - Rework the logic to call mailx. +# - Print the version with the "-V" option. +# - Define the version in the PROGRAMVERSION variable +# +# Version 3.31 +# - Fixed the test for the -servername flag -- Kitson Consulting. +# +# Version 3.30 +# - Use highest returncode for Nagios output -- Marcel Pennewiss +# - Set RETCODE to 3 (unknown) if a certificate file does not exist -- Marcel Pennewiss +# - Add a "-d" option to specify a directory or file mask pattern -- Marcel Pennewiss +# - Add a "-N" option to create summarized Nagios output -- Marcel Pennewiss +# - Cleaned up many formatting -- Marcel Pennewiss +# +# Versione 3.29a +# - Added option to specify email sender address +# +# Version 3.29 +# - Add the openssl -servername flag if it shows up in help. +# +# Version 3.28 +# - Added a DEBUG option to assist with debugging folks who use the script +# +# Version 3.27 +# - Allow white spaces to exist in the certificate file list +# - Add an additional check to pick up bad / non-existent certificates +# - Add a check to look for the existence of a mail program. Error out if it's not present. +# - Enable the TLS -servername extension by default - Juergen Knaack & Johan Denoyer +# +# Version 3.26 +# - Allow the certificate type (PEM, DER, NET) to be passed on the command line +# +# Version 3.25 +# - Check for "no route to host" errors -- Dan Doyle +# - Set RETCODE to 3 (unknown) if a connection error occurs -- Dan Doyle +# - Documentation fixes +# +# Version 3.24 +# - Utilize the -clcerts option to limit the results to client certificates - Eitan Katznelson +# +# Version 3.23 +# - Fixed typo in date2julian routine -- Ken Cook +# +# Version 3.22 +# - Change the validation option to "-V" +# - Add a "-v" option to specify a specific protocol version (ssl2, ssl3 or tls) +# +# Version 3.21 +# - Adjust e-mail checking to avoid exiting if notifications aren't enabled -- Nick Anderson +# - Added the number of days until expiration to the Nagios output -- Nick Anderson +# +# Version 3.20 +# - Fixed a bug in certificate length checking -- Tim Nowaczyk +# +# Version 3.19 +# - Added check to verify the certificate retrieved is valid +# +# Version 3.18 +# - Add support for connecting to FTP servers -- Paul A Sand +# +# Version 3.17 +# - Add support for connecting to imap servers -- Joerg Pareigis +# +# Version 3.16 +# - Add support for connecting to the mail sbmission port -- Luis E. Munoz +# +# Version 3.15 +# - Adjusted the file checking logic to use the correct certificate -- Maciej Szudejko +# - Add sbin to the default search paths for OpenBSD compatibility -- Alex Popov +# - Use cut instead of substring processing to ensure compatibility -- Alex Popov +# +# Version 3.14 +# - Fixed the Common Name parser to handle DN's where the CN is not the last item +# eg. EmailAddr -- Jason Brothers +# - Added the ability to grab the serial number -- Jason Brothers +# - Added the "-b" option to print results without a header -- Jason Brothers +# - Added the "-v" option for certificate validation -- Jason Brothers +# +# Version 3.13 +# - Updated the subject line to include the hostname as well as +# the common name embedded in the X509 certificate (if it's +# available) -- idea proposed by Mike Burns +# +# Version 3.12 +# - Updated the license to allow redistribution and modification +# +# Version 3.11 +# - Added ability to comment out lines in files passed +# to the "-f" option -- Brett Stauner +# - Fixed comment next to file processing logic +# +# Version 3.10 +# - Fixed POP3 port -- Simon Matter +# +# Version 3.9 +# - Switched binary location logic to use which utility +# +# Version 3.8 +# - Fixed display on 80 column displays +# - Cleaned up the formatting +# +# Version 3.7 +# - Fixed bug in NAGIOS tests -- Ben Allen +# +# Version 3.6 +# - Added support for certificates stored in PKCS#12 databases -- Ken Gallo +# - Cleaned up comments +# - Adjusted variables to be more consistent +# +# Version 3.5 +# - Added support for NAGIOS -- Quanah Gibson-Mount +# - Added additional checks for mail -- Quanah Gibson-Mount +# - Convert tabs to spaces -- Quanah Gibson-Mount +# - Cleaned up usage() routine +# - Added additional checks for openssl +# +# Version 3.4 +# - Added a missing "{" to line 364 -- Ken Gallo +# - Move mktemp to the start of the main body to avoid errors +# - Adjusted default binary paths to make sure the script just works +# w/ Solaris, BSD and Linux hosts +# +# Version 3.3 +# - Added common name from X.509 certificate file to E-mail body / header -- Doug Curtis +# - Fixed several documentation errors +# - Use mktemp to create temporary files +# - Convert printf, sed and awk to variables +# - Check for printf, sed, awk and mktemp binaries +# - Add additional logic to make sure mktemp returned a valid temporary file +# +# Version 3.2 +# - Added option to list certificates in the file passed to "-f". +# +# Version 3.1 +# - Added handling for starttls for smtp -- Marco Amrein +# - Added handling for starttls for pop3 (without s) -- Marco Amrein +# - Removed extra spacing at end of script +# +# Version 3.0 +# - Added "-i" option to print certificate issuer +# - Removed $0 from Subject line of outbound e-mails +# - Fixed some typographical errors +# - Removed redundant "-b" option +# +# Version 2.0 +# - Fixed an issue with e-mails formatting incorrectly +# - Added additional space to host column -- Darren-Perot Spruell +# - Replaced GNU date dependency with CHRIS F. A. JOHNSON's +# date2julian shell function. This routine can be found on +# page 170 of Chris's book "Shell Scripting Recipes: A +# Problem-Solution Approach," ISBN #1590594711. Julian function +# was created based on a post to comp.unix.shell by Tapani Tarvainen. +# - Cleaned up function descriptions +# - Removed several lines of redundant code +# - Adjusted the help message +# +# Version 1.1 +# - Added "-c" flag to report expiration status of a PEM encoded +# certificate -- Hampus Lundqvist +# - Updated the prints messages to display the reason a connection +# failed (connection refused, connection timeout, bad cert, etc) +# - Updated the GNU date checking routines +# - Added checks for each binary required +# - Added checks for connection timeouts +# - Added checks for GNU date +# - Added a "-h" option +# - Cleaned up the documentation +# +# Version 1.0 +# Initial Release +# +# Purpose: +# ssl-cert-check checks to see if a digital certificate in X.509 format +# has expired. ssl-cert-check can be run in interactive and batch mode, +# and provides facilities to alarm if a certificate is about to expire. +# +# License: +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Requirements: +# Requires openssl +# +# Installation: +# Copy the shell script to a suitable location +# +# Tested platforms: +# -- Solaris 9 using /bin/bash +# -- Solaris 10 using /bin/bash +# -- OS X 10.4.2 using /bin/bash +# -- OpenBSD using /bin/sh +# -- FreeBSD using /bin/sh +# -- Centos Linux 3, 4, 5 & 6 using /bin/bash +# -- Redhat Enterprise Linux 3, 4, 5 & 6 using /bin/bash +# -- Gentoo using /bin/bash +# +# Usage: +# Refer to the usage() sub-routine, or invoke ssl-cert-check +# with the "-h" option. +# +# Examples: +# Please refer to the following site for documentation and examples: +# http://prefetch.net/articles/checkcertificate.html + +# Cleanup temp files if they exist +trap cleanup EXIT INT TERM QUIT + +PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/ssl/bin:/usr/sfw/bin +export PATH + +# Who to page when an expired certificate is detected (cmdline: -e) +ADMIN="root" + +# Email sender address for alarm notifications +SENDER="" + +# Number of days in the warning threshhold (cmdline: -x) +WARNDAYS=30 + +# If QUIET is set to TRUE, don't print anything on the console (cmdline: -q) +QUIET="FALSE" + +# Don't send E-mail by default (cmdline: -a) +ALARM="FALSE" + +# Don't run as a Nagios plugin by default (cmdline: -n) +NAGIOS="FALSE" + +# Don't summarize Nagios output by default (cmdline: -N) +NAGIOSSUMMARY="FALSE" + +# NULL out the PKCSDBPASSWD variable for later use (cmdline: -k) +PKCSDBPASSWD="" + +# Type of certificate (PEM, DER, NET) (cmdline: -t) +CERTTYPE="pem" + +# Location of system binaries +AWK=$(command -v awk) +DATE=$(command -v date) +GREP=$(command -v grep) +OPENSSL=$(command -v openssl) +PRINTF=$(command -v printf) +SED=$(command -v sed) +MKTEMP=$(command -v mktemp) +FIND=$(command -v find) + +# Try to find a mail client +if [ -f /usr/bin/mailx ]; then + MAIL="/usr/bin/mailx" + MAILMODE="mailx" +elif [ -f /bin/mail ]; then + MAIL="/bin/mail" + MAILMODE="mail" +elif [ -f /usr/bin/mail ]; then + MAIL="/usr/bin/mail" + MAILMODE="mail" +elif [ -f /sbin/mail ]; then + MAIL="/sbin/mail" + MAILMODE="mail" +elif [ -f /usr/sbin/mail ]; then + MAIL="/usr/sbin/mail" + MAILMODE="mail" +elif [ -f /usr/sbin/sendmail ]; then + MAIL="/usr/sbin/sendmail" + MAILMODE="sendmail" +else + MAIL="cantfindit" + MAILMODE="cantfindit" +fi + +# Return code used by nagios. Initialize to 0. +RETCODE=0 + +# Certificate counters and minimum difference. Initialize to 0. +SUMMARY_VALID=0 +SUMMARY_WILL_EXPIRE=0 +SUMMARY_EXPIRED=0 +SUMMARY_MIN_DIFF=0 +SUMMARY_MIN_DATE= +SUMMARY_MIN_HOST= +SUMMARY_MIN_PORT= + +# Set the default umask to be somewhat restrictive +umask 077 + + +##################################################### +# Purpose: Remove temporary files if the script doesn't +# exit() cleanly +##################################################### +cleanup() { + if [ -f "${CERT_TMP}" ]; then + rm -f "${CERT_TMP}" + fi + + if [ -f "${ERROR_TMP}" ]; then + rm -f "${ERROR_TMP}" + fi +} + + +##################################################### +### Send email +### Accepts three parameters: +### $1 -> sender email address +### $2 -> email to send mail +### $3 -> Subject +### $4 -> Message +##################################################### +send_mail() { + + FROM="${1}" + TO="${2}" + SUBJECT="${3}" + MSG="${4}" + + case "${MAILMODE}" in + "mail") + echo "$MSG" | "${MAIL}" -r "$FROM" -s "$SUBJECT" "$TO" + ;; + "mailx") + echo "$MSG" | "${MAIL}" -s "$SUBJECT" "$TO" + ;; + "sendmail") + (echo "Subject:$SUBJECT" && echo "TO:$TO" && echo "FROM:$FROM" && echo "$MSG") | "${MAIL}" "$TO" + ;; + "*") + echo "ERROR: You enabled automated alerts, but the mail binary could not be found." + echo "FIX: Please modify the \${MAIL} and \${MAILMODE} variable in the program header." + exit 1 + ;; + esac +} + +############################################################################# +# Purpose: Convert a date from MONTH-DAY-YEAR to Julian format +# Acknowledgements: Code was adapted from examples in the book +# "Shell Scripting Recipes: A Problem-Solution Approach" +# ( ISBN 1590594711 ) +# Arguments: +# $1 -> Month (e.g., 06) +# $2 -> Day (e.g., 08) +# $3 -> Year (e.g., 2006) +############################################################################# +date2julian() { + + if [ "${1}" != "" ] && [ "${2}" != "" ] && [ "${3}" != "" ]; then + ## Since leap years add aday at the end of February, + ## calculations are done from 1 March 0000 (a fictional year) + d2j_tmpmonth=$((12 * $3 + $1 - 3)) + + ## If it is not yet March, the year is changed to the previous year + d2j_tmpyear=$(( d2j_tmpmonth / 12)) + + ## The number of days from 1 March 0000 is calculated + ## and the number of days from 1 Jan. 4713BC is added + echo $(( (734 * d2j_tmpmonth + 15) / 24 + - 2 * d2j_tmpyear + d2j_tmpyear/4 + - d2j_tmpyear/100 + d2j_tmpyear/400 + $2 + 1721119 )) + else + echo 0 + fi +} + +############################################################################# +# Purpose: Convert a string month into an integer representation +# Arguments: +# $1 -> Month name (e.g., Sep) +############################################################################# +getmonth() +{ + case ${1} in + Jan) echo 1 ;; + Feb) echo 2 ;; + Mar) echo 3 ;; + Apr) echo 4 ;; + May) echo 5 ;; + Jun) echo 6 ;; + Jul) echo 7 ;; + Aug) echo 8 ;; + Sep) echo 9 ;; + Oct) echo 10 ;; + Nov) echo 11 ;; + Dec) echo 12 ;; + *) echo 0 ;; + esac +} + +############################################################################# +# Purpose: Calculate the number of seconds between two dates +# Arguments: +# $1 -> Date #1 +# $2 -> Date #2 +############################################################################# +date_diff() +{ + if [ "${1}" != "" ] && [ "${2}" != "" ]; then + echo $((${2} - ${1})) + else + echo 0 + fi +} + +##################################################################### +# Purpose: Print a line with the expiraton interval +# Arguments: +# $1 -> Hostname +# $2 -> TCP Port +# $3 -> Status of certification (e.g., expired or valid) +# $4 -> Date when certificate will expire +# $5 -> Days left until the certificate will expire +# $6 -> Issuer of the certificate +# $7 -> Common Name +# $8 -> Serial Number +##################################################################### +prints() +{ + if [ "${NAGIOSSUMMARY}" = "TRUE" ]; then + return + fi + + if [ "${QUIET}" != "TRUE" ] && [ "${ISSUER}" = "TRUE" ] && [ "${VALIDATION}" != "TRUE" ]; then + MIN_DATE=$(echo "$4" | "${AWK}" '{ printf "%3s %2d %4d", $1, $2, $4 }') + if [ "${NAGIOS}" = "TRUE" ]; then + ${PRINTF} "%-35s %-17s %-8s %-11s %s\n" "$1:$2" "$6" "$3" "$MIN_DATE" "|days=$5" + else + ${PRINTF} "%-35s %-17s %-8s %-11s %4d\n" "$1:$2" "$6" "$3" "$MIN_DATE" "$5" + fi + elif [ "${QUIET}" != "TRUE" ] && [ "${ISSUER}" = "TRUE" ] && [ "${VALIDATION}" = "TRUE" ]; then + ${PRINTF} "%-35s %-35s %-32s %-17s\n" "$1:$2" "$7" "$8" "$6" + + elif [ "${QUIET}" != "TRUE" ] && [ "${VALIDATION}" != "TRUE" ]; then + MIN_DATE=$(echo "$4" | "${AWK}" '{ printf "%3s %2d, %4d", $1, $2, $4 }') + if [ "${NAGIOS}" = "TRUE" ]; then + ${PRINTF} "%-47s %-12s %-12s %s\n" "$1:$2" "$3" "$MIN_DATE" "|days=$5" + else + ${PRINTF} "%-47s %-12s %-12s %4d\n" "$1:$2" "$3" "$MIN_DATE" "$5" + fi + elif [ "${QUIET}" != "TRUE" ] && [ "${VALIDATION}" = "TRUE" ]; then + ${PRINTF} "%-35s %-35s %-32s\n" "$1:$2" "$7" "$8" + fi +} + + +#################################################### +# Purpose: Print a heading with the relevant columns +# Arguments: +# None +#################################################### +print_heading() +{ + if [ "${NOHEADER}" != "TRUE" ]; then + if [ "${QUIET}" != "TRUE" ] && [ "${ISSUER}" = "TRUE" ] && [ "${NAGIOS}" != "TRUE" ] && [ "${VALIDATION}" != "TRUE" ]; then + ${PRINTF} "\n%-35s %-17s %-8s %-11s %-4s\n" "Host" "Issuer" "Status" "Expires" "Days" + echo "----------------------------------- ----------------- -------- ----------- ----" + + elif [ "${QUIET}" != "TRUE" ] && [ "${ISSUER}" = "TRUE" ] && [ "${NAGIOS}" != "TRUE" ] && [ "${VALIDATION}" = "TRUE" ]; then + ${PRINTF} "\n%-35s %-35s %-32s %-17s\n" "Host" "Common Name" "Serial #" "Issuer" + echo "----------------------------------- ----------------------------------- -------------------------------- -----------------" + + elif [ "${QUIET}" != "TRUE" ] && [ "${NAGIOS}" != "TRUE" ] && [ "${VALIDATION}" != "TRUE" ]; then + ${PRINTF} "\n%-47s %-12s %-12s %-4s\n" "Host" "Status" "Expires" "Days" + echo "----------------------------------------------- ------------ ------------ ----" + + elif [ "${QUIET}" != "TRUE" ] && [ "${NAGIOS}" != "TRUE" ] && [ "${VALIDATION}" = "TRUE" ]; then + ${PRINTF} "\n%-35s %-35s %-32s\n" "Host" "Common Name" "Serial #" + echo "----------------------------------- ----------------------------------- --------------------------------" + fi + fi +} + +#################################################### +# Purpose: Print a summary for nagios +# Arguments: +# None +#################################################### +print_summary() +{ + if [ "${NAGIOSSUMMARY}" != "TRUE" ]; then + return + fi + + if [ ${SUMMARY_WILL_EXPIRE} -eq 0 ] && [ ${SUMMARY_EXPIRED} -eq 0 ]; then + ${PRINTF} "%s valid certificate(s)|days=%s\n" "${SUMMARY_VALID}" "${SUMMARY_MIN_DIFF}" + + elif [ ${SUMMARY_EXPIRED} -ne 0 ]; then + ${PRINTF} "%s certificate(s) expired (%s:%s on %s)|days=%s\n" "${SUMMARY_EXPIRED}" "${SUMMARY_MIN_HOST}" "${SUMMARY_MIN_PORT}" "${SUMMARY_MIN_DATE}" "${SUMMARY_MIN_DIFF}" + + elif [ ${SUMMARY_WILL_EXPIRE} -ne 0 ]; then + ${PRINTF} "%s certificate(s) will expire (%s:%s on %s)|days=%s\n" "${SUMMARY_WILL_EXPIRE}" "${SUMMARY_MIN_HOST}" "${SUMMARY_MIN_PORT}" "${SUMMARY_MIN_DATE}" "${SUMMARY_MIN_DIFF}" + + fi +} + +############################################################# +# Purpose: Set returncode to value if current value is lower +# Arguments: +# $1 -> New returncorde +############################################################# +set_returncode() +{ + if [ "${RETCODE}" -lt "${1}" ]; then + RETCODE="${1}" + fi +} + +######################################################################## +# Purpose: Set certificate counters and informations for nagios summary +# Arguments: +# $1 -> Status of certificate (0: valid, 1: will expire, 2: expired) +# $2 -> Hostname +# $3 -> TCP Port +# $4 -> Date when certificate will expire +# $5 -> Days left until the certificate will expire +######################################################################## +set_summary() +{ + if [ "${1}" -eq 0 ]; then + SUMMARY_VALID=$((SUMMARY_VALID+1)) + elif [ "${1}" -eq 1 ]; then + SUMMARY_WILL_EXPIRE=$((SUMMARY_WILL_EXPIRE+1)) + else + SUMMARY_EXPIRED=$((SUMMARY_EXPIRED+1)) + fi + + if [ "${5}" -lt "${SUMMARY_MIN_DIFF}" ] || [ "${SUMMARY_MIN_DIFF}" -eq 0 ]; then + SUMMARY_MIN_DATE="${4}" + SUMMARY_MIN_DIFF="${5}" + SUMMARY_MIN_HOST="${2}" + SUMMARY_MIN_PORT="${3}" + fi +} + +########################################## +# Purpose: Describe how the script works +# Arguments: +# None +########################################## +usage() +{ + echo "Usage: $0 [ -e email address ] [-E sender email address] [ -x days ] [-q] [-a] [-b] [-h] [-i] [-n] [-N] [-v]" + echo " { [ -s common_name ] && [ -p port] } || { [ -f cert_file ] } || { [ -c cert file ] } || { [ -d cert dir ] }" + echo "" + echo " -a : Send a warning message through E-mail" + echo " -b : Will not print header" + echo " -c cert file : Print the expiration date for the PEM or PKCS12 formatted certificate in cert file" + echo " -d cert directory : Print the expiration date for the PEM or PKCS12 formatted certificates in cert directory" + echo " -e E-mail address : E-mail address to send expiration notices" + echo " -E E-mail sender : E-mail address of the sender" + echo " -f cert file : File with a list of FQDNs and ports" + echo " -h : Print this screen" + echo " -i : Print the issuer of the certificate" + echo " -k password : PKCS12 file password" + echo " -n : Run as a Nagios plugin" + echo " -N : Run as a Nagios plugin and output one line summary (implies -n, requires -f or -d)" + echo " -p port : Port to connect to (interactive mode)" + echo " -q : Don't print anything on the console" + echo " -s commmon name : Server to connect to (interactive mode)" + echo " -S : Print validation information" + echo " -t type : Specify the certificate type" + echo " -V : Print version information" + echo " -x days : Certificate expiration interval (eg. if cert_date < days)" + echo "" +} + + +########################################################################## +# Purpose: Connect to a server ($1) and port ($2) to see if a certificate +# has expired +# Arguments: +# $1 -> Server name +# $2 -> TCP port to connect to +########################################################################## +check_server_status() { + + PORT="$2" + case "$PORT" in + smtp|25|submission|587) TLSFLAG="-starttls smtp";; + pop3|110) TLSFLAG="-starttls pop3";; + imap|143) TLSFLAG="-starttls imap";; + ftp|21) TLSFLAG="-starttls ftp";; + xmpp|5222) TLSFLAG="-starttls xmpp";; + xmpp-server|5269) TLSFLAG="-starttls xmpp-server";; + irc|194) TLSFLAG="-starttls irc";; + postgres|5432) TLSFLAG="-starttls postgres";; + mysql|3306) TLSFLAG="-starttls mysql";; + lmtp|24) TLSFLAG="-starttls lmtp";; + nntp|119) TLSFLAG="-starttls nntp";; + sieve|4190) TLSFLAG="-starttls sieve";; + ldap|389) TLSFLAG="-starttls ldap";; + *) TLSFLAG="";; + esac + + if [ "${TLSSERVERNAME}" = "FALSE" ]; then + OPTIONS="-connect ${1}:${2} $TLSFLAG" + else + OPTIONS="-connect ${1}:${2} -servername ${1} $TLSFLAG" + fi + + echo "" | "${OPENSSL}" s_client $OPTIONS 2> "${ERROR_TMP}" 1> "${CERT_TMP}" + + if "${GREP}" -i "Connection refused" "${ERROR_TMP}" > /dev/null; then + prints "${1}" "${2}" "Connection refused" "Unknown" + set_returncode 3 + elif "${GREP}" -i "No route to host" "${ERROR_TMP}" > /dev/null; then + prints "${1}" "${2}" "No route to host" "Unknown" + set_returncode 3 + elif "${GREP}" -i "gethostbyname failure" "${ERROR_TMP}" > /dev/null; then + prints "${1}" "${2}" "Cannot resolve domain" "Unknown" + set_returncode 3 + elif "${GREP}" -i "Operation timed out" "${ERROR_TMP}" > /dev/null; then + prints "${1}" "${2}" "Operation timed out" "Unknown" + set_returncode 3 + elif "${GREP}" -i "ssl handshake failure" "${ERROR_TMP}" > /dev/null; then + prints "${1}" "${2}" "SSL handshake failed" "Unknown" + set_returncode 3 + elif "${GREP}" -i "connect: Connection timed out" "${ERROR_TMP}" > /dev/null; then + prints "${1}" "${2}" "Connection timed out" "Unknown" + set_returncode 3 + elif "${GREP}" -i "Name or service not known" "${ERROR_TMP}" > /dev/null; then + prints "${1}" "${2}" "Unable to resolve the DNS name ${1}" "Unknown" + set_returncode 3 + else + check_file_status "${CERT_TMP}" "${1}" "${2}" + fi +} + +##################################################### +### Check the expiration status of a certificate file +### Accepts three parameters: +### $1 -> certificate file to process +### $2 -> Server name +### $3 -> Port number of certificate +##################################################### +check_file_status() { + + CERTFILE="${1}" + HOST="${2}" + PORT="${3}" + + ### Check to make sure the certificate file exists + if [ ! -r "${CERTFILE}" ] || [ ! -s "${CERTFILE}" ]; then + echo "ERROR: The file named ${CERTFILE} is unreadable or doesn't exist" + echo "ERROR: Please check to make sure the certificate for ${HOST}:${PORT} is valid" + set_returncode 3 + return + fi + + ### Grab the expiration date from the X.509 certificate + if [ "${PKCSDBPASSWD}" != "" ]; then + # Extract the certificate from the PKCS#12 database, and + # send the informational message to /dev/null + "${OPENSSL}" pkcs12 -nokeys -in "${CERTFILE}" \ + -out "${CERT_TMP}" -clcerts -password pass:"${PKCSDBPASSWD}" 2> /dev/null + + # Extract the expiration date from the certificate + CERTDATE=$("${OPENSSL}" x509 -in "${CERT_TMP}" -enddate -noout | \ + "${SED}" 's/notAfter\=//') + + # Extract the issuer from the certificate + CERTISSUER=$("${OPENSSL}" x509 -in "${CERT_TMP}" -issuer -noout | \ + "${AWK}" 'BEGIN {RS=", " } $0 ~ /^O =/ + { print substr($0,5,17)}') + + ### Grab the common name (CN) from the X.509 certificate + COMMONNAME=$("${OPENSSL}" x509 -in "${CERT_TMP}" -subject -noout | \ + "${SED}" -e 's/.*CN = //' | \ + "${SED}" -e 's/, .*//') + + ### Grab the serial number from the X.509 certificate + SERIAL=$("${OPENSSL}" x509 -in "${CERT_TMP}" -serial -noout | \ + "${SED}" -e 's/serial=//') + else + # Extract the expiration date from the ceriticate + CERTDATE=$("${OPENSSL}" x509 -in "${CERTFILE}" -enddate -noout -inform "${CERTTYPE}" | \ + "${SED}" 's/notAfter\=//') + + # Extract the issuer from the certificate + CERTISSUER=$("${OPENSSL}" x509 -in "${CERTFILE}" -issuer -noout -inform "${CERTTYPE}" | \ + "${AWK}" 'BEGIN {RS=", " } $0 ~ /^O =/ { print substr($0,5,17)}') + + ### Grab the common name (CN) from the X.509 certificate + COMMONNAME=$("${OPENSSL}" x509 -in "${CERTFILE}" -subject -noout -inform "${CERTTYPE}" | \ + "${SED}" -e 's/.*CN = //' | \ + "${SED}" -e 's/, .*//') + + ### Grab the serial number from the X.509 certificate + SERIAL=$("${OPENSSL}" x509 -in "${CERTFILE}" -serial -noout -inform "${CERTTYPE}" | \ + "${SED}" -e 's/serial=//') + fi + + ### Split the result into parameters, and pass the relevant pieces to date2julian + set -- ${CERTDATE} + MONTH=$(getmonth "${1}") + + # Convert the date to seconds, and get the diff between NOW and the expiration date + CERTJULIAN=$(date2julian "${MONTH#0}" "${2#0}" "${4}") + CERTDIFF=$(date_diff "${NOWJULIAN}" "${CERTJULIAN}") + + if [ "${CERTDIFF}" -lt 0 ]; then + if [ "${ALARM}" = "TRUE" ]; then + send_mail "${SENDER}" "${ADMIN}" "Certificate for ${HOST} \"(CN: ${COMMONNAME})\" has expired!" \ + "The SSL certificate for ${HOST} \"(CN: ${COMMONNAME})\" has expired!" + fi + + prints "${HOST}" "${PORT}" "Expired" "${CERTDATE}" "${CERTDIFF}" "${CERTISSUER}" "${COMMONNAME}" "${SERIAL}" + RETCODE_LOCAL=2 + + elif [ "${CERTDIFF}" -lt "${WARNDAYS}" ]; then + if [ "${ALARM}" = "TRUE" ]; then + send_mail "${SENDER}" "${ADMIN}" "Certificate for ${HOST} \"(CN: ${COMMONNAME})\" will expire in ${CERTDIFF}-days or less" \ + "The SSL certificate for ${HOST} \"(CN: ${COMMONNAME})\" will expire on ${CERTDATE}" + fi + prints "${HOST}" "${PORT}" "Expiring" "${CERTDATE}" "${CERTDIFF}" "${CERTISSUER}" "${COMMONNAME}" "${SERIAL}" + RETCODE_LOCAL=1 + + else + prints "${HOST}" "${PORT}" "Valid" "${CERTDATE}" "${CERTDIFF}" "${CERTISSUER}" "${COMMONNAME}" "${SERIAL}" + RETCODE_LOCAL=0 + fi + + set_returncode "${RETCODE_LOCAL}" + MIN_DATE=$(echo "${CERTDATE}" | "${AWK}" '{ print $1, $2, $4 }') + set_summary "${RETCODE_LOCAL}" "${HOST}" "${PORT}" "${MIN_DATE}" "${CERTDIFF}" +} + +################################# +### Start of main program +################################# +while getopts abc:d:e:E:f:hik:nNp:qs:St:Vx: option +do + case "${option}" in + a) ALARM="TRUE";; + b) NOHEADER="TRUE";; + c) CERTFILE=${OPTARG};; + d) CERTDIRECTORY=${OPTARG};; + e) ADMIN=${OPTARG};; + E) SENDER=${OPTARG};; + f) SERVERFILE=$OPTARG;; + h) usage + exit 1;; + i) ISSUER="TRUE";; + k) PKCSDBPASSWD=${OPTARG};; + n) NAGIOS="TRUE";; + N) NAGIOS="TRUE" + NAGIOSSUMMARY="TRUE";; + p) PORT=$OPTARG;; + q) QUIET="TRUE";; + s) HOST=$OPTARG;; + S) VALIDATION="TRUE";; + t) CERTTYPE=$OPTARG;; + V) echo "${PROGRAMVERSION}" + exit 0 + ;; + x) WARNDAYS=$OPTARG;; + \?) usage + exit 1;; + esac +done + +### Check to make sure a openssl utility is available +if [ ! -f "${OPENSSL}" ]; then + echo "ERROR: The openssl binary does not exist in ${OPENSSL}." + echo "FIX: Please modify the \${OPENSSL} variable in the program header." + exit 1 +fi + +### Check to make sure a date utility is available +if [ ! -f "${DATE}" ]; then + echo "ERROR: The date binary does not exist in ${DATE} ." + echo "FIX: Please modify the \${DATE} variable in the program header." + exit 1 +fi + +### Check to make sure a grep and find utility is available +if [ ! -f "${GREP}" ] || [ ! -f "${FIND}" ]; then + echo "ERROR: Unable to locate the grep and find binary." + echo "FIX: Please modify the \${GREP} and \${FIND} variables in the program header." + exit 1 +fi + +### Check to make sure the mktemp and printf utilities are available +if [ ! -f "${MKTEMP}" ] || [ -z "${PRINTF}" ]; then + echo "ERROR: Unable to locate the mktemp or printf binary." + echo "FIX: Please modify the \${MKTEMP} and \${PRINTF} variables in the program header." + exit 1 +fi + +### Check to make sure the sed and awk binaries are available +if [ ! -f "${SED}" ] || [ ! -f "${AWK}" ]; then + echo "ERROR: Unable to locate the sed or awk binary." + echo "FIX: Please modify the \${SED} and \${AWK} variables in the program header." + exit 1 +fi + +### Check to make sure a mail client is available it automated notifications are requested +if [ "${ALARM}" = "TRUE" ] && [ ! -f "${MAIL}" ]; then + echo "ERROR: You enabled automated alerts, but the mail binary could not be found." + echo "FIX: Please modify the ${MAIL} variable in the program header." + exit 1 +fi + +# Send along the servername when TLS is used +if ${OPENSSL} s_client -help 2>&1 | grep '-servername' > /dev/null; then + TLSSERVERNAME="TRUE" +else + TLSSERVERNAME="FALSE" +fi + +# Place to stash temporary files +CERT_TMP=$($MKTEMP /var/tmp/cert.XXXXXX) +ERROR_TMP=$($MKTEMP /var/tmp/error.XXXXXX) + +### Baseline the dates so we have something to compare to +MONTH=$(${DATE} "+%m") +DAY=$(${DATE} "+%d") +YEAR=$(${DATE} "+%Y") +NOWJULIAN=$(date2julian "${MONTH#0}" "${DAY#0}" "${YEAR}") + +### Touch the files prior to using them +if [ -n "${CERT_TMP}" ] && [ -n "${ERROR_TMP}" ]; then + touch "${CERT_TMP}" "${ERROR_TMP}" +else + echo "ERROR: Problem creating temporary files" + echo "FIX: Check that mktemp works on your system" + exit 1 +fi + +### If a HOST was passed on the cmdline, use that value +if [ "${HOST}" != "" ]; then + print_heading + check_server_status "${HOST}" "${PORT:=443}" + print_summary +### If a file is passed to the "-f" option on the command line, check +### each certificate or server / port combination in the file to see if +### they are about to expire +elif [ -f "${SERVERFILE}" ]; then + print_heading + + IFS=$'\n' + for LINE in $(grep -E -v '(^#|^$)' "${SERVERFILE}") + do + HOST=${LINE%% *} + PORT=${LINE##* } + IFS=" " + if [ "$PORT" = "FILE" ]; then + check_file_status "${HOST}" "FILE" "${HOST}" + else + check_server_status "${HOST}" "${PORT}" + fi + done + IFS="${OLDIFS}" + print_summary +### Check to see if the certificate in CERTFILE is about to expire +elif [ "${CERTFILE}" != "" ]; then + print_heading + check_file_status "${CERTFILE}" "FILE" "${CERTFILE}" + print_summary + +### Check to see if the certificates in CERTDIRECTORY are about to expire +elif [ "${CERTDIRECTORY}" != "" ] && ("${FIND}" -L "${CERTDIRECTORY}" -type f > /dev/null 2>&1); then + print_heading + for FILE in $("${FIND}" -L "${CERTDIRECTORY}" -type f); do + check_file_status "${FILE}" "FILE" "${FILE}" + done + print_summary +### There was an error, so print a detailed usage message and exit +else + usage + exit 1 +fi + +### Exit with a success indicator +if [ "${NAGIOS}" = "TRUE" ]; then + exit "${RETCODE}" +else + exit 0 +fi diff --git a/shell/wakuag.sh b/shell/wakuag.sh new file mode 100644 index 0000000..1b9d681 --- /dev/null +++ b/shell/wakuag.sh @@ -0,0 +1,102 @@ +downloads() +{ + if [ -f "/usr/bin/curl" ] + then + echo $1,$2 + http_code=`curl -I -m 10 -o /dev/null -s -w %{http_code} $1` + if [ "$http_code" -eq "200" ] + then + curl --connect-timeout 10 --retry 100 $1 > $2 + elif [ "$http_code" -eq "405" ] + then + curl --connect-timeout 10 --retry 100 $1 > $2 + else + curl --connect-timeout 10 --retry 100 $3 > $2 + fi + elif [ -f "/usr/bin/cd1" ] + then + http_code = `cd1 -I -m 10 -o /dev/null -s -w %{http_code} $1` + if [ "$http_code" -eq "200" ] + then + cd1 --connect-timeout 10 --retry 100 $1 > $2 + elif [ "$http_code" -eq "405" ] + then + cd1 --connect-timeout 10 --retry 100 $1 > $2 + else + cd1 --connect-timeout 10 --retry 100 $3 > $2 + fi + elif [ -f "/usr/bin/wget" ] + then + wget --timeout=10 --tries=100 -O $2 $1 + if [ $? -ne 0 ] + then + wget --timeout=10 --tries=100 -O $2 $3 + fi + elif [ -f "/usr/bin/wd1" ] + then + wd1 --timeout=10 --tries=100 -O $2 $1 + if [ $? -eq 0 ] + then + wd1 --timeout=10 --tries=100 -O $2 $3 + fi + fi +} + + +function clean_cron(){ + chattr -R -ia /var/spool/cron + tntrecht -R -ia /var/spool/cron + chattr -ia /etc/crontab + tntrecht -ia /etc/crontab + chattr -R -ia /etc/cron.d + tntrecht -R -ia /etc/cron.d + chattr -R -ia /var/spool/cron/crontabs + tntrecht -R -ia /var/spool/cron/crontabs + crontab -r + rm -rf /var/spool/cron/* + rm -rf /etc/cron.d/* + rm -rf /var/spool/cron/crontabs + rm -rf /etc/crontab +} + +function lock_cron() +{ + chattr -R +ia /var/spool/cron + tntrecht -R +ia /var/spool/cron + touch /etc/crontab + chattr +ia /etc/crontab + tntrecht +ia /etc/crontab + chattr -R +ia /var/spool/cron/crontabs + tntrecht -R +ia /var/spool/cron/crontabs + chattr -R +ia /etc/cron.d + tntrecht -R +ia /etc/cron.d +} + +function CheckAboutSomeKeys(){ + if [ -f "/root/.ssh/id_rsa" ] + then + echo 'found: /root/.ssh/id_rsa' + fi + + if [ -f "/home/*/.ssh/id_rsa" ] + then + echo 'found: /home/*/.ssh/id_rsa' + fi + + if [ -f "/root/.aws/credentials" ] + then + echo 'found: /root/.aws/credentials' + fi + + if [ -f "/home/*/.aws/credentials" ] + then + echo 'found: /home/*/.aws/credentials' + fi +} + +## 内网互信主机执行命令 +if [ -f /root/.ssh/known_hosts ] && [ -f /root/.ssh/id_rsa.pub ]; then + for h in $(grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" /root/.ssh/known_hosts); do + ssh -oBatchMode=yes -oConnectTimeout=5 -oStrictHostKeyChecking=no $h 'hostname' & + done +fi \ No newline at end of file diff --git a/shell/get_proc_mem.sh b/shell/系统信息/get_proc_mem.sh similarity index 100% rename from shell/get_proc_mem.sh rename to shell/系统信息/get_proc_mem.sh diff --git a/shell/系统信息/show_pid_openfile.sh b/shell/系统信息/show_pid_openfile.sh new file mode 100644 index 0000000..4cf93ef --- /dev/null +++ b/shell/系统信息/show_pid_openfile.sh @@ -0,0 +1,45 @@ +#!/bin/env bash +################################################################### +#Script Name : show_pid_openfile.sh +#Description : Show Pid OpenFile Top 10. +#Create Date : 2021-07-29 +#Author : lework +#Email : lework@yeah.net +################################################################### + + +function printbar() { + title=$1 + value=$2 + + tput setaf $((1+ ${value} % 7)) + printf " %10s " "${title}" + eval "printf '█%.0s' {1..${value}}" + printf " %s %s\n\n" ${value} + tput sgr0 +} + + +while true +do + # Show a title + tput clear + printf " %10s " "" + tput setaf 7; tput smul; + printf "%s\n\n" "Show Pid OpenFile Top 10 ($(date +%T))" + tput rmul + data="" + for proc in $(find /proc/ -maxdepth 1 -type d -name "[0-9]*") + do + fd=$(ls $proc/fd 2>/dev/null | wc -l) + if [[ $fd -gt 1 ]]; then + pid=$(echo $proc | awk -F/ '{print $3}') + data="${data}\n${pid} ${fd}" + fi + done + echo -e ${data} | sort -k2 -n -r | head -10 | while read line + do + printbar $line + done + sleep 10 +done