Linux Advanced
פערי production שהקורסים מדלגים עליהם: SSH, firewall, systemd, logs, Bash מתקדם ו-networking
תיאוריה
מדוע Linux Advanced חיוני בשוק העבודה הישראלי
לפי סריקת שוק העבודה (אפריל 2026), Linux מופיע בשיעור גבוה ממשרות ה-DevOps בישראל — כישורי Linux מתקדמים נדרשים כתנאי בסיס כמעט בכל תפקיד infrastructure, platform engineering, ו-SRE. הקורסים הרגילים מלמדים ls, grep, ו-SSH בסיסי, ועוצרים שם. אבל בראיון ובעבודה האמיתית, המראיינים בודקים: האם אתה יודע לנהל מפתחות SSH בצוות? איך מגנים על שרת מ-brute-force? איך כותבים systemd unit ל-service שלא יפול? איך מונעים disk exhaustion מ-logs? איך מבצעים debug לבעיות רשת בproduction?
הסעיפים הבאים מכסים את עשרת הפערים שסריקת המשרות הישראלית זיהתה: SSH key rotation, UFW/iptables, fail2ban, systemd units, logrotate, Bash strict mode, flock, DNS debugging, TCP/IP troubleshooting, ו-sudo least-privilege. אלה הם בדיוק הנושאים שמבדילים בין DevOps junior שיודע להפעיל שרת לבין מי שיודע להפעיל אותו בצורה בטוחה ואמינה.
SSH key rotation וניהול authorized_keys
הקורסים מלמדים ssh-keygen פעם אחת. בproduction, מפתחות SSH הם credentials לכל דבר — ולכן חייבים לנהל אותם כמו passwords: לסובב, לבדוק, ולהסיר כשהם לא רלוונטיים.
**יצירת מפתח חדש (Ed25519 — מומלץ לproduction):**
# Ed25519 קצר יותר מ-RSA-4096 אך חזק לפחות כמוהו
ssh-keygen -t ed25519 -C "deploy@myservice-$(date +%Y-%m)" -f ~/.ssh/id_ed25519_deploy**הוספת מפתח לשרת:**
ssh-copy-id -i ~/.ssh/id_ed25519_deploy.pub user@server
# או ידנית:
cat ~/.ssh/id_ed25519_deploy.pub >> ~/.ssh/authorized_keys**ניהול authorized_keys בצוות — המקרה שהקורסים מדלגים עליו:**
כאשר מהנדס עוזב את הצוות, יש להסיר את המפתח שלו מכל השרתים. בשרת יחיד:
# זיהוי מפתח לפי comment (email/שם המשתמש שמוגדר ב-ssh-keygen -C)
grep 'john@company' ~/.ssh/authorized_keys
# הסרה:
sed -i '/john@company/d' ~/.ssh/authorized_keysבfleet של שרתים — השתמשו בAnsible או ב-script מרכזי. עיקרון הזהב: authorized_keys שמנוהל ידנית על כל שרת בנפרד הוא security risk.
**הגבלת scope של מפתח** — כל שורה ב-authorized_keys יכולה לכלול אפשרויות:
# מפתח שמריץ רק פקודה אחת (deploy script)
command="/opt/deploy.sh",no-pty,no-agent-forwarding ssh-ed25519 AAAA... ci@github-actions
# מפתח שמותר רק מ-IP מסוים
from="203.0.113.10",no-x11-forwarding ssh-ed25519 AAAA... admin@company**אימות תצורת SSH daemon:**
# ודא שהגדרות אלה קיימות ב-/etc/ssh/sshd_config
grep -E '^(PermitRootLogin|PasswordAuthentication|PubkeyAuthentication)' /etc/ssh/sshd_config
# PermitRootLogin no
# PasswordAuthentication no
# PubkeyAuthentication yes
# בדיקת syntax לפני reload:
sshd -t && systemctl reload sshdUFW ו-iptables: ניהול חוקי firewall
כל שרת Ubuntu production רץ עם firewall. UFW (Uncomplicated Firewall) הוא frontend ל-iptables שמפשט את הניהול, אבל חיוני להבין גם את ה-iptables שמתחת.
**מצב UFW נוכחי:**
sudo ufw status verbose
# Status: active
# To Action From
# 22/tcp ALLOW IN Anywhere
# 443/tcp ALLOW IN Anywhere
# 80/tcp ALLOW IN Anywhere**הוספת כללים:**
# אפשר HTTPS מכל מקום
sudo ufw allow 443/tcp
# אפשר SSH רק מ-IP ספציפי (מומלץ לproduction)
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp
# חסום IP ספציפי
sudo ufw deny from 198.51.100.0/24
# מחק כלל
sudo ufw delete allow 443/tcp**הפעלת UFW בפעם הראשונה — סדר קריטי:**
# תמיד הוסף כלל ל-SSH לפני הפעלת UFW — אחרת תנעל את עצמך מחוץ לשרת!
sudo ufw allow 22/tcp
sudo ufw enable
# יש לאשר: Command may disrupt existing ssh connections. Proceed with operation (y|n)? y**iptables — הבנת הבסיס:**
UFW כותב כללי iptables. להצגת הכללים בפועל:
sudo iptables -L -n -v --line-numbers
# Chain INPUT (policy DROP)
# num pkts bytes target prot opt in out source destination
# 1 5421 2.1M ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
# 2 1823 98K ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22keyword חשוב: policy DROP לעומת ACCEPT. שרת production צריך INPUT policy DROP (הכחשה כברירת מחדל) עם ACCEPT רק לפורטים הנדרשים.
**debugging connection refused vs. connection timeout:**
- Connection refused: ה-firewall שולח RST — הפורט חסום בצד השרת עם REJECT
- Connection timeout: ה-packet נופל ללא תגובה — הפורט חסום עם DROP
# בדיקת ניתוב פאקטים:
sudo iptables -L INPUT -n -v | grep dpt:8080fail2ban: הגנת brute-force על SSH
כל שרת עם פורט SSH פתוח לאינטרנט סופג ניסיונות כניסה רצופים — bots סורקים כל ה-IP space ומנסים שמות משתמש וסיסמאות ידועות. fail2ban קורא את ה-logs ועוצר תוקפים אוטומטית.
**התקנה וקינפוג בסיסי:**
sudo apt install fail2ban -y
# תמיד עבדו עם jail.local — לא jail.conf (שמוחלף בupgrades)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local**הגדרת jail ל-SSH ב-jail.local:**
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
findtime = 10m
bantime = 1h
ignoreip = 127.0.0.1/8 ::1 203.0.113.10הסברים:
- maxretry = 3 — לאחר 3 כשלות בתוך findtime, ה-IP נחסם
- findtime = 10m — חלון הזמן לספירת הכשלות
- bantime = 1h — משך החסימה. לproduction נוקשה: bantime = 1d או -1 (חסימה לצמיתות)
- ignoreip — IPs שלעולם לא ייחסמו (VPN של הצוות, monitoring servers)
**ניהול fail2ban בזמן אמת:**
# סטטוס כללי
sudo fail2ban-client status
# סטטוס jail ספציפי
sudo fail2ban-client status sshd
# Status for the jail: sshd
# |- Filter
# | |- Currently failed: 2
# | `- Total failed: 47
# `- Actions
# |- Currently banned: 3
# `- Total banned: 12
# שחרור IP שנחסם בטעות (למשל, המנהל שלך)
sudo fail2ban-client set sshd unbanip 203.0.113.10
# בדיקת IP ספציפי
sudo fail2ban-client get sshd banip | grep 198.51.100.5**fail2ban לweb applications:**
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5fail2ban כותב חוקי iptables זמניים כדי לחסום IPs — ניתן לראות אותם עם sudo iptables -L f2b-sshd -n.
systemd unit files לשירותים ארוכי טווח
כל תהליך שצריך לרוץ באופן רציף בproduction צריך systemd unit — לא nohup, לא screen, לא tmux. systemd מטפל ב-restart אוטומטי, logging, dependency ordering, ו-resource limits.
**מבנה unit file בסיסי:**
# /etc/systemd/system/myapp.service
[Unit]
Description=My Production API Service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/venv/bin/python -m uvicorn main:app --host 0.0.0.0 --port 8000
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp
# משתני סביבה (אל תכניסו secrets כאן — השתמשו ב-EnvironmentFile)
EnvironmentFile=/etc/myapp/env
Environment=PYTHONUNBUFFERED=1
# Resource limits
LimitNOFILE=65536
MemoryMax=512M
CPUQuota=50%
[Install]
WantedBy=multi-user.target**הפעלה וניהול:**
# reload הגדרות daemon (חובה אחרי כל שינוי ב-unit file)
sudo systemctl daemon-reload
# הפעלה + enable לboot
sudo systemctl enable --now myapp
# סטטוס עם logs אחרונים
sudo systemctl status myapp
# קריאת logs
sudo journalctl -u myapp -f # follow real-time
sudo journalctl -u myapp --since today # היום בלבד
sudo journalctl -u myapp -n 100 # 100 שורות אחרונות**Type=simple vs. Type=forking vs. Type=notify:**
- simple — התהליך הראשי הוא ה-service. מומלץ לרוב ה-cases.
- forking — לתהליכים שמבצעים fork ועוברים לרקע (legacy daemons).
- notify — התהליך שולח sd_notify(READY=1) כשמוכן; systemd ממתין לאות זה.
**ExecStartPre לbefore-start checks:**
[Service]
ExecStartPre=/usr/bin/test -f /etc/myapp/env
ExecStartPre=/opt/myapp/scripts/check-db-connection.sh
ExecStart=/opt/myapp/venv/bin/python -m uvicorn main:appאם ExecStartPre נכשל — systemd לא מפעיל את ה-service ורושם את השגיאה.
logrotate: ניהול application logs
ללא logrotate, application logs ממלאים את ה-disk. logrotate הוא כלי שרץ ב-cron (יומי בברירת מחדל) ומנהל rotation, compression, ושמירת היסטוריה.
**קינפוג logrotate לapplication:**
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
dateext
dateformat -%Y%m%d
su myapp myapp
}הסברים:
- daily — rotate כל יום. חלופות: weekly, monthly, size 100M
- rotate 14 — שמור 14 קבצים היסטוריים (2 שבועות)
- compress — דחס קבצים ישנים עם gzip
- delaycompress — אל תדחס את ה-rotate האחרון מיד (אפליקציות שמחזיקות file handle פתוח)
- missingok — אל תתריע אם הקובץ לא קיים
- notifempty — אל תבצע rotate לקובץ ריק
- copytruncate — העתק ואז truncate (לאפליקציות שלא תומכות ב-SIGHUP reopen)
- dateext + dateformat — שמות קבצים עם תאריך: app.log-20260417.gz
**הרצה ידנית לבדיקה:**
# dry-run: ראה מה יקרה בלי לבצע
sudo logrotate -d /etc/logrotate.d/myapp
# הרצה מיידית (bypass בדיקת 24 שעות)
sudo logrotate -f /etc/logrotate.d/myapp
# בדיקת סטטוס (מתי בוצע rotate לאחרונה)
cat /var/lib/logrotate/status | grep myapp**postrotate לSIGHUP:**
אפליקציות שכותבות ישירות לקובץ צריכות לקבל SIGHUP כדי לפתוח קובץ חדש:
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
postrotate
systemctl reload myapp 2>/dev/null || true
endscript
}Bash strict mode ו-trap: scripts שלא מתפוצצים בשקט
הבעיה עם Bash scripts שנכתבים בלי strict mode: פקודה שנכשלת לא עוצרת את ה-script. ב-CI/CD pipeline, deployment script שמדלג בשקט על שגיאה יכול להשאיר סביבת production במצב חלקי.
**strict mode — template סטנדרטי:**
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'הסבר כל דגל:
- set -e (errexit) — עצור ה-script כאשר פקודה מחזירה exit code שאינו 0
- set -u (nounset) — עצור כאשר משתנה לא מוגדר משמש (מונע rm -rf $TYPO/)
- set -o pipefail — pipe נכשל אם אחת מהפקודות בו נכשלה (בלי דגל זה, false | true מחזיר 0)
- IFS=$'\n\t' — Internal Field Separator מוגדר ל-newline ו-tab (לא space) — מונע split שגוי על שמות קבצים עם רווחים
**trap לcleanup:**
trap מאפשר לרשום function שתרוץ כשה-script יוצא — בין אם בהצלחה, בשגיאה, או ב-Ctrl+C.
#!/usr/bin/env bash
set -euo pipefail
# Cleanup function
cleanup() {
local exit_code=$?
echo "[cleanup] Script exited with code: $exit_code"
# מחיקת קבצים זמניים
rm -f /tmp/deploy_lock_$$
rm -f /tmp/deploy_payload_$$.json
if [[ $exit_code -ne 0 ]]; then
echo "[ERROR] Deployment failed — rolling back"
# rollback logic here
fi
}
# רשום cleanup לכל מקרי יציאה
trap cleanup EXIT
trap 'echo "[SIGINT] Interrupted"; exit 130' INT
trap 'echo "[SIGTERM] Terminated"; exit 143' TERM
# ... שאר ה-script ...
TMP_FILE=$(mktemp /tmp/deploy_payload_$$.json)
echo '{"version": "1.4.2"}' > "$TMP_FILE"
# trap יטפל במחיקה בכל מקרה**דוגמה מבוססת production — deploy script עם strict mode:**
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="/opt/myapp"
BACKUP_DIR="/opt/myapp-backups"
cleanup() {
echo "Cleaning temp files..."
rm -f /tmp/new_release_$$.tar.gz
}
trap cleanup EXIT
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <version>" >&2
exit 1
fi
VERSION="$1"
echo "Deploying version: $VERSION"
# כל שגיאה כאן תפסיק ותריץ cleanup
cp -r "$APP_DIR" "$BACKUP_DIR/$VERSION-$(date +%s)"Bash flock: מניעת הרצה מקבילה של scripts
בעיה קלאסית: cron job שרץ כל דקה, אך לפעמים לוקח 90 שניות להשלמה. ללא הגנה, שני instances רצים במקביל ויוצרים race condition. flock פותר זאת.
**שיטה 1: flock בתוך ה-script:**
#!/usr/bin/env bash
set -euo pipefail
LOCK_FILE="/var/lock/myapp-sync.lock"
# נסה לקבל lock. -n = non-blocking (אל תחכה)
if ! flock -n "$LOCK_FILE" true; then
echo "Another instance is already running. Exiting."
exit 0
fi
# כאן בטוח שרק instance אחד רץ
exec flock -n "$LOCK_FILE" bash << 'SCRIPT'
echo "Doing exclusive work..."
sleep 10
echo "Done."
SCRIPT**שיטה 2: flock כ-wrapper בcron (מומלץ יותר):**
# /etc/cron.d/myapp-sync
* * * * * myapp flock -n /var/lock/myapp-sync.lock /opt/myapp/scripts/sync.sh >> /var/log/myapp/sync.log 2>&1**שיטה 3: שימוש ב-file descriptor (הנפוצה ביותר):**
#!/usr/bin/env bash
set -euo pipefail
exec 9>/var/lock/myapp-sync.lock
if ! flock -n 9; then
echo "Script already running (PID $(cat /var/lock/myapp-sync.lock)). Exiting." >&2
exit 0
fi
# שמור PID לקובץ ה-lock לdebug
echo $$ >&9
echo "Running sync at $(date)"
# ... עבודה בלעדית ...**בדיקת lock קיים:**
# בדוק אם process מחזיק lock
fuser /var/lock/myapp-sync.lock
# 12345 <- PID המחזיק ב-lock
# או:
lsof /var/lock/myapp-sync.lockflock מבוסס על kernel-level advisory locks — עובד בין processes שונים על אותו host, לא ב-distributed environments. לlock מבוזר (multi-server), יש להשתמש ב-Redis SET NX או Zookeeper.
DNS debugging עם dig ו-TTL propagation
DNS הוא אחד הנושאים שהכי הרבה DevOps אנשים מסתבכים בו בproduction. deployment שכולל שינוי DNS record יכול לקחת דקות עד שעות להתפשט — והמוקד צריך לדעת למה.
**dig — כלי ה-DNS הבסיסי לproduction:**
# שאילתה בסיסית
dig example.com A
# הצג רק את ה-answer section (ללא noise)
dig +short example.com A
# 203.0.113.10
# שאילתה לservers ספציפי (עוקף local cache)
dig @8.8.8.8 example.com A # Google DNS
dig @1.1.1.1 example.com A # Cloudflare DNS
dig @ns1.example.com example.com A # שאל את ה-authoritative server ישירות
# הצג TTL
dig +ttl example.com A
# example.com. 300 IN A 203.0.113.10
# ^^^--- TTL בשניות (5 דקות)
# רשומות נוספות
dig example.com MX # mail exchange
dig example.com NS # nameservers
dig example.com TXT # SPF, DKIM, verification
dig example.com AAAA # IPv6**TTL propagation — הסבר לproduction:**
TTL (Time To Live) הוא הזמן שב-resolver (הDNS של ISP המשתמש) שומר את התשובה ב-cache. אם TTL = 3600 (שעה) ומשנים את ה-A record, חלק מהמשתמשים יראו את הrecord הישן עד שעה!
אסטרטגיה לפני migration:
# שלב 1 (24-48 שעות לפני): הורד TTL ל-300 שניות (5 דקות)
# שלב 2: בצע את ה-migration
# שלב 3: לאחר ווידוא, הגבה TTL בחזרה ל-3600
# בדוק את ה-TTL הנוכחי:
dig +ttl example.com A | grep -v '^;' | grep 'IN A'**trace מלא של DNS resolution:**
# +trace מראה כל שלב: root → TLD → authoritative
dig +trace example.com A**debugging נפוץ:**
# בדוק מה ה-resolver המקומי מחזיר
dig example.com A
# אם שונה ממה שאתה מצפה — שאל authoritative ישירות
dig @ns1.example.com example.com A
# flush local DNS cache (Ubuntu/systemd-resolved)
sudo resolvectl flush-caches
# או:
sudo systemd-resolve --flush-cachesTCP/IP troubleshooting עם ss ו-tcpdump
כשמשהו לא עובד ברשת בproduction, ss ו-tcpdump הם הכלים הראשונים שמגיעים.
**ss — replacement מודרני ל-netstat:**
# כל ה-listening ports (TCP)
ss -tlnp
# State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
# LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
# LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=5678,fd=6))
# כל החיבורים הפעילים
ss -tnp
# connections ל-port ספציפי
ss -tnp sport = :8080
# connections מ-IP ספציפי
ss -tnp dst 203.0.113.10
# הצג socket statistics (drops, errors)
ss -sפירוש flags:
- -t — TCP (השתמשו -u ל-UDP)
- -l — listening sockets בלבד
- -n — numeric (אל תפשור שמות)
- -p — הצג process name ו-PID
**tcpdump — capture packets בזמן אמת:**
# צפה בכל traffic על ממשק eth0
sudo tcpdump -i eth0
# filter ל-port ספציפי
sudo tcpdump -i eth0 port 8080
# filter ל-IP ספציפי
sudo tcpdump -i eth0 host 203.0.113.10
# שמור ל-file לanalysis בWireshark
sudo tcpdump -i eth0 port 443 -w /tmp/capture.pcap
# קרא pcap file (Wireshark GUI, או בcli:)
tcpdump -r /tmp/capture.pcap**debugging flow מוכח לproduction:**
# שלב 1: האם process מאזין?
ss -tlnp | grep ':8080'
# שלב 2: האם firewall חוסם?
sudo iptables -L INPUT -n | grep 8080
# שלב 3: האם ה-connection מגיע?
sudo tcpdump -i any port 8080 -n -c 10
# שלב 4: מה ה-response?
curl -v http://localhost:8080/health**ESTABLISHED connections תקועים:**
# ראה connections ב-state ESTABLISHED עם זמן
ss -tnp state established | awk 'NR>1 {print $4, $5, $6}'
# TIME_WAIT connections מרובים — סימן לthroughput גבוה
ss -tn state time-wait | wc -lLinux users ו-sudo: least-privilege management
עיקרון least-privilege: כל user ו-process צריך רק את ההרשאות המינימליות הנדרשות למשימתו. בproduction, הרצת services כ-root היא anti-pattern מסוכן.
**יצירת service user ייעודי:**
# יצירת system user (ללא home directory, ללא login shell)
sudo useradd --system --no-create-home --shell /usr/sbin/nologin --comment "MyApp Service Account" myapp
# ודא שנוצר נכון
getent passwd myapp
# myapp:x:998:998:MyApp Service Account:/:/usr/sbin/nologin
# הגדר בעלות על application directory
sudo chown -R myapp:myapp /opt/myapp
sudo chmod 750 /opt/myapp**sudo configuration — /etc/sudoers:**
# תמיד ערוך עם visudo (בדיקת syntax אוטומטית)
sudo visudo
# או קובץ נפרד ב-/etc/sudoers.d/ (מומלץ)
sudo visudo -f /etc/sudoers.d/deploy-team**דוגמאות sudoers production:**
# מאפשר ל-deploy user לrestart service ספציפי בלבד
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp
# מאפשר ל-monitoring user לקרוא logs בלבד
monitor ALL=(ALL) NOPASSWD: /usr/bin/journalctl -u myapp *
# מאפשר ל-CI/CD user לreload nginx בלבד
ci ALL=(ALL) NOPASSWD: /usr/bin/systemctl reload nginx**audit של users והרשאות:**
# מי הusers עם login shell (אמורים להיות בני אדם בלבד)
grep -v '/nologin\|/false' /etc/passwd | cut -d: -f1,6,7
# מי יש ב-sudo group
getent group sudo
# בדיקת SUID/SGID files (פוטנציאל privilege escalation)
find / -perm -4000 -o -perm -2000 2>/dev/null | grep -v proc
# בדיקת world-writable directories
find /opt /etc /var -type d -perm -002 2>/dev/null**umask ל-service accounts:**
# הוסף ל-/etc/systemd/system/myapp.service
[Service]
UMask=0027 # קבצים חדשים: rw-r----- (640), directories: rwxr-x--- (750)security summary: שרת production לא אמור להיות ניתן לlogin כ-root ישירות (PermitRootLogin no), כל service צריך user משלו ללא login shell, וסיסמאות ב-sudo (NOPASSWD) מוגבלות לפקודות ספציפיות בלבד.
תרגול מעשי
1. ניתוח קובץ authorized_keys ואיתור מפתחות ללא הגבלת scope
קובץ authorized_keys מדומה מכיל 4 מפתחות SSH. עבד אותו עם grep ו-awk כדי לזהות: (1) כמה מפתחות כוללים הגבלת command= (מפתחות מוגבלי scope), (2) כמה מפתחות אין להם שום אפשרות — גישה מלאה בלי הגבלה. הדפס PASS או FAIL לכל בדיקה. זוהי ביקורת authorized_keys — משימה שגרתית לאחר offboarding של מהנדס.
2. ניתוח systemd unit file ואימות הגדרות production
unit file מדומה מכיל הגדרות service. עבד אותו עם grep ו-python3 כדי לאמת: (1) Restart מוגדר ל-on-failure, (2) User מוגדר ולא root, (3) EnvironmentFile קיים (ולא environment variables מוגדרים ישירות בunit), (4) LimitNOFILE מוגדר מעל 1024. כל בדיקה תדפיס PASS או FAIL. זו ביקורת unit file לפני פריסה ל-production.
3. ניתוח /etc/passwd לזיהוי service accounts ללא login shell
קרא את /etc/passwd וזהה: (1) כמה users מוגדרים עם login shell אמיתי (/bin/bash או /bin/sh) — אלה אמורים להיות בני אדם בלבד, (2) כמה users מוגדרים עם /usr/sbin/nologin או /bin/false (service accounts תקניים), (3) אם יש service accounts חשודים — users עם UID מעל 999 (non-system) שמוגדרים עם login shell. הדפס ממצאים ו-PASS/FAIL לכל בדיקה.
שאלות חיבור
חבר את מה שלמדת בנושא זה לנושאים קודמים. אין תשובה אחת נכונה — חשיבה ביקורתית היא המטרה.
שאלת חיבור 1
ב-Linux Advanced למדת על systemd unit files לניהול שירותים ארוכי טווח — כולל Restart=on-failure, EnvironmentFile לsecrets, ו-ExecStartPre לvalidation. ב-Docker למדת על Docker Compose עם restart: unless-stopped, env_file, ו-depends_on עם condition: service_healthy. כיצד שתי הגישות משלימות זו את זו בסביבת production שמריצה גם containers וגם native processes, ומה עדיין נשאר באחריות systemd גם כשרוב האפליקציות כבר ב-Docker?
שאלת חיבור 2
ב-Linux Advanced למדת על Bash strict mode (set -euo pipefail) ו-trap cleanup handlers. ב-CI/CD pipelines (GitHub Actions, Jenkins) כל step הוא בעצם Bash script שרץ בסביבה מבוקרת. כיצד היעדר strict mode ב-deployment scripts גורם לbugs שקשה לאתר ב-CI/CD, ואיך trap משתלב עם הדרישה של pipelines לrollback אוטומטי כשstep נכשל?
מוכן לבחינה?
בצע הערכה תיאורטית, תרגול CLI ושאלות חיבור כדי לסיים את הנושא.