当前位置: 首页 > article >正文

AWS S3 和 Lambda 使用

目录:
AWS概述
EMR Serverless
AWS VPC及其网络
关于AWS网络架构的思考
AWS S3 和 Lambda 使用

本文将通过一个实例来说明如何使用 AWS S3 和 Lambda。


使用场景:通过代码将文件上传到S3,该文件需要是公开访问的,并对上传的文件进行安全检测。

文件上传到S3

S3 bucket 设置

首先创建一个S3的bucket,例如 my-test-cn-north-1-bucket。为了公开访问,该bucket必须关闭"Block public access (bucket settings)",除了bucket级别之外,账号级别也需要关闭。这个设置是 public read 的前提。

Bucket policy 必须设置Principal和Action,Principal可以设置为当前账户下的用户或角色。如果允许当前账户下的所有的用户/角色,可以这样设置:

{"Effect": "Allow","Principal": { "AWS": "arn:aws:iam::123456789012:root" },"Action": ["s3:GetObject","s3:GetObjectAcl","s3:PutObject","s3:PutObjectAcl"],"Resource": "arn:aws:s3:::my-test-cn-north-1-bucket/*"
}

由于Bucket policy限制,此时bucket中的文件只有当前账户下的用户或角色才能读写。因此需要在上传文件时将文件的权限设置为public read的,也就是说要修改文件的ACL。编辑 Object Ownership,开启 “ACLs enabled”,至于对象拥有关系,选择 “Bucket owner preferred” 即可。

上传文件,并在文件的权限设置中将ACL修改为"public access"。这样设置完成之后,即可以保证bucket的put操作是受限的,同时read操作是公开的。

S3 API 文件上传

本地通过代码进行文件上传:

private static S3AsyncClient getAsyncClient() {AssumeRoleRequest assumeRoleRequest = AssumeRoleRequest.builder().roleArn("arn:aws-cn:iam:: 123456789012:role/product/operation").roleSessionName("AssumeRoleSession").build();StsClient stsClient = StsClient.builder().credentialsProvider(ProfileCredentialsProvider.builder().profileName("your-profile") // replace with your profile.build()).build();StsAssumeRoleCredentialsProvider creProvider =StsAssumeRoleCredentialsProvider.builder().stsClient(stsClient).refreshRequest(assumeRoleRequest).build();return S3AsyncClient.crtBuilder().credentialsProvider(creProvider).build();
}

而在生产环境中,当然是不能将角色ARNaws profile写到代码中的。因此需要用过 IRSA(IAM Roles for Service Accounts) 来实现 AWS API 调用。

创建一个ServiceAccount:

apiVersion: v1
kind: ServiceAccount
metadata:name: my-s3-accessnamespace: your-nsannotations:eks.amazonaws.com/role-arn: arn:aws-cn:iam:: 123456789012:role/my-test-cn-north-1-eks-access-s3

在角色my-test-cn-north-1-eks-access-s3policies中,需要设置bucket的访问策略:

{"Effect": "Allow","Action": "s3:*","Resource": ["arn:aws-cn:s3:::my-test-cn-north-1-bucket/*"]
}

然后在deployment中指定serviceAccount:

apiVersion: apps/v1
kind: Deployment
metadata:name: ms-test
spec:template:metadata:labels:...spec:serviceAccountName: my-s3-access

如此 EKS 的 workloads 即可以 ServiceAccount 绑定的角色身份来执行 S3 的 API 调用。

文件上传代码如下:

private static void putObjectToS3(InputStream is, String key, String bucketName, boolean publicRead) {try (S3TransferManager transferManager = S3TransferManager.builder().s3Client(S3AsyncClient.crtCreate()).build()) {UploadRequest uploadRequest = UploadRequest.builder().putObjectRequest(req -> {req.bucket(bucketName).key(key);if (publicRead) {req.acl("public-read"); // set public read acl}}).addTransferListener(LoggingTransferListener.create()).requestBody(AsyncRequestBody.fromInputStream(config -> config.inputStream(is).executor(newFixedThreadPool(8)))).build();transferManager.upload(uploadRequest).completionFuture().join();}
}

某些类型的文件如果不指定contentType,通过url访问时需要下载。如果指定了contentType,则可以在浏览器中打开。

文件安全扫描

创建lambda函数

文件上传到 S3之后,可以通过 lambda 来进行安全扫描。

首先创建一个 AWS lambda,选择最简单的 Author from scratch 模板,同时选择需要的运行时环境和系统架构,这里选择arm64架构。对于权限,如果需要复用role,就选择已有的role,否则就默认创建角色。

创建好 lambda 之后,需要在 Diagram 界面添加触发器,选择需要监听的 S3 bucket。

在 lambda 的配置页面,选择 Permissions 可以看到执行lambda的角色,也是创建lambda时默认创建的角色。查看该角色的权限 policies,可以发现与lambda日志相关的权限已经有了,但是还需要以下权限:

{"Effect": "Allow","Action": ["s3:GetObject","sns:Publish"],"Resource": ["arn:aws-cn:s3:::my-test-cn-north-1-bucket/*"]
}

创建 lambda layer

对文件进行安全扫描需要用到Clamav。正常情况下需要下载 Clamav 的源码然后编译成二进制文件。但是从官方下载的source包中没有configure文件,无法编译和安装。因此可以用第二种方式,直接在容器中安装 Clamav,然后将必要的文件拷贝出来制作 lambda layer。

使用docker run -it --name lambda-clamav amazonlinux:2 bash 来创建一个docker容器。

容器使用 amazonlinux:2 镜像是为了保持与 AWS Lambda的环境保持一致。

在容器中执行以下命令:

# 安装 ClamAV 和必要工具
yum install -y clamav clamav-update tar gzip# 确认版本
clamscan --version# 更新病毒库
freshclam# 创建打包目录
mkdir -p /opt/clamav-layer/bin
mkdir -p /opt/clamav-layer/lib# 复制 ClamAV 主程序
cp /usr/bin/clamscan /opt/clamav-layer/bin/
cp /usr/bin/freshclam /opt/clamav-layer/bin/# 复制动态链接库
ldd /usr/bin/clamscan | awk '{print $3}' | xargs -I {} cp {} /opt/clamav-layer/lib/
ldd /usr/bin/freshclam | awk '{print $3}' | xargs -I {} cp {} /opt/clamav-layer/lib/# 复制病毒库配置文件(可选)
mkdir -p /opt/clamav-layer/etc
cp /etc/freshclam.conf /opt/clamav-layer/etc/

将文件从容器复制到本地:

docker cp lambda-clamav:/opt/clamav-layer ./clamav-layer# 进入目录并打包
cd clamav-layer
zip -r ../clamav-layer.zip .

注意,只有更新病毒库后才能使用clamscan test.txt来扫描文件,否则没有基础的病毒库文件无法扫描。下载的病毒库文件默认放在/var/lib/clamav 目录下,总共有四个文件:

bytecode.cvd  daily.cvd  freshclam.dat  main.cvd

这里打包clamav-layer时并没有将病毒库一起打包进来,原因是 AWS Layer 限制了大小,压缩包不能超过50MB,解压后不能超过250MB。

layer 制作完成后,在 Lambda 的控制台的layer仓库中上传。上传时需要注意 layer的系统架构,可以在生成layer文件的容器中查看:

file /opt/clamav-layer/bin/clamscan# 以下结果表明为 ARM 架构
opt/clamav-layer/bin/clamscan: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.7.0, BuildID[sha1]=ac6484d18dd79864db6d56599e020f8a968f652c, stripped

上传完成后我们回到 lambda 函数,在code tab页的最下面上传 layer。layer的架构和运行时必须与lambda函数的架构和运行时是兼容的。如果lambda 函数是 x86_64的,就无法使用 arm 架构的layer。

layer的压缩包会直接解压到 lambda 实例的 /opt 目录下,其结构会变成: /opt/bin/clamscan, /opt/lib/…

lambda 函数实现

由于受到layer的大小限制导致病毒库无法打包到layer中,因此考虑实时下载或从S3下载。

将病毒库文件打包成clamav_db.tar.gz并上传到S3,然后实现 lambda 函数:

import os
import subprocess
import boto3
import tarfile
from botocore.exceptions import ClientErrors3 = boto3.client('s3')
S3_BUCKET = "ms-test-cn-north-1-bucket"
CLAMSCAN_PATH = "/opt/bin/clamscan"
FRESHCLAM_PATH = "/opt/bin/freshclam"
LIB_DIR = "/opt/lib"
DB_KEY = "clamav_db.tar.gz"
TMP_DB_PATH = "/tmp/clamav_db.tar.gz"
DB_DIR = "/tmp/clamav_db"def download_and_extract_db():try:s3.download_file(S3_BUCKET, DB_KEY, TMP_DB_PATH)os.makedirs(DB_DIR, exist_ok=True)with tarfile.open(TMP_DB_PATH, "r:gz") as tar:tar.extractall(DB_DIR)os.remove(TMP_DB_PATH)except ClientError as e:print(f"S3 下载失败: {e}")raisedef lambda_handler(event, context):os.environ["LD_LIBRARY_PATH"] = LIB_DIRif not os.path.exists(f"{DB_DIR}/main.cvd"):print(f"start download clamav db")download_and_extract_db()bucket = event['Records'][0]['s3']['bucket']['name']key = event['Records'][0]['s3']['object']['key']tmp_path = f"/tmp/{os.path.basename(key)}"try:s3.download_file(bucket, key, tmp_path)print(f"the file need to be checked: ", tmp_path)scan_cmd = [CLAMSCAN_PATH, "-d", DB_DIR, tmp_path]try:result = subprocess.run(scan_cmd, env={"LD_LIBRARY_PATH": LIB_DIR}, capture_output=True, text=True, timeout=180)print("stdout:", result.stdout)print("stderr:", result.stderr) if "Infected files: 0" not in result.stdout:print(f"感染文件: {key} - 结果: {result.stdout}")return {"status": "INFECTED"}else:print(f"安全文件: {key}")return {"status": "CLEAN"}except subprocess.TimeoutExpired:print("timeout!")except ClientError as e:print(f"S3 错误: {e}")return {"status": "ERROR"}finally:if os.path.exists(tmp_path):os.remove(tmp_path)

对于lambda来说,只有 /tmp目录是可写的,且最大为512MB。当 Lambda 服务复用同一个执行环境即热启动时,该目录是保留的。这种复用通常发生在短时间内连续多次调用同一个函数时。

当Lambda服务创建一个新的执行环境时,/tmp 目录会被清空并重新初始化。

如果想持久化病毒库,而不是每次重新下载,可以考虑挂载EFS。

测试

在 lambda 函数的 code 页面可以创建test event用来模拟S3 trigger,并可以保存下来复用。注意,测试事件中bucketName和文件需要是真实存在的。

相关文章:

AWS S3 和 Lambda 使用

目录: AWS概述 EMR Serverless AWS VPC及其网络 关于AWS网络架构的思考 AWS S3 和 Lambda 使用 本文将通过一个实例来说明如何使用 AWS S3 和 Lambda。 使用场景:通过代码将文件上传到S3,该文件需要是公开访问的,并对上传的文件进…...

Mysql 在什么样的情况下会产生死锁?

在 MySQL 中,死锁是指两个或多个事务相互等待对方释放锁,导致所有相关事务无法继续执行的情况。死锁会影响数据库的并发性能,因此需要及时检测并处理。假设有两个事务 T1 和 T2: 事务 T1 首先锁定 表 A 的行 1。然后尝试锁定 表 B…...

符号秩检验

内容来源 非参数统计(第2版) 清华大学出版社 王星 褚挺进 编著 符号秩检验 在符号检验的基础上,增加了数据绝对值大小的信息 检验统计量 用一个简单的例子来说明 样本数据 X i , i 1 , ⋯ , 6 X_i,i1,\cdots,6 Xi​,i1,⋯,6 如下 X …...

RainbowDash 的 Robot

H RainbowDash 的 Robot - 第七届校赛正式赛 —— 补题 题目大意: 给一个 n ∗ m n*m n∗m 的二维网格,在第 i i i 列中,前 a i a_i ai​ 单元格被阻断,无法通行,即 [ 1 , a i ] [1,a_i] [1,ai​] 。 一个机器人正…...

yum repolist all全部禁用了 怎么办

文章目录 步骤思考解决yum仓库全部被禁用的问题步骤思考: 检查仓库状态:运行yum repolist all,查看所有仓库的启用状态。 被禁用的仓库会显示为disabled。 启用所有仓库:可以逐一启用,或者使用命令批量启用。 例如使用yum-config-manager --enable ‘*’,但需要注意是否有…...

SQL WHERE 与 HAVING

WHERE 和 HAVING 都是 SQL 中用于筛选数据的子句,但它们有重要的区别 WHERE 子句 在 分组前 过滤数据 作用于 原始数据行 不能使用聚合函数 执行效率通常比 HAVING 高 SELECT column1, column2 FROM table WHERE condition; HAVING 子句 在 分组后 过滤数据 …...

如何在 Unity3D 导入 Spine 动画

一、前言 《如何在 Unity3D 项目中导入 Spine 动画》,虽然在网上有很多这种文章,直接将问题交给 DeepSeek 也能得到具体的操作流程,但是照着他们提供的方法还是能遇到几个问题,比如: AI 回答没有提到 Unity 无法识别.…...

子网划分2

子网分配的问题,下列vlsm如何设置? 某公司申请了一个C类202.60.31.0的IP地址,要求设置三个子网,一个为100台主机,一个为50台主机,另一个为50台主机,用VLSM如何设置? 哪位高手指教一…...

C++的UDP连接解析域名地址错误

背景 使用c开发一个udp连接功能的脚本,可以接收发送数据,而且地址是经过内网穿透到外网的 经过 通常发送数据给目标地址,需要把目的地址结构化,要么使用inet_addr解析ip地址,要么使用inet_pton sockaddr_in target…...

23种设计模式中的观察者模式

定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。 观察者模式是一种发布-订阅模式。它让发送通知的一方(被观察者)和接收通知的一方(观察者)能够解耦&#xf…...

论文笔记:ASTTN模型

研究现状 现有研究大多通过分别考虑空间相关性和时间相关性或在滑动时间窗口内对这种时空相关性进行建模,而未能对直接的时空相关性进行建模。受最近图领域Transformer成功的启发,该模型提出利用局部多头自关注,在自适应时空图上直接建立跨时…...

Java单例模式详解

单例模式详解 一、单例模式概述 单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。 核心特点 唯一实例:保证一个类只有一个实例存在全局访问:提供统一的访问入…...

Linux命令-tar

tar 命令的完整参数列表: 参数 描述 -c 创建新的归档文件 -x 解压归档文件 -t 列出归档文件内容 -r 追加文件到归档文件 -u 更新归档文件中的文件 -d 从归档文件中删除文件 -f 指定归档文件的名称 -v 显示详细信息(verbose) -z 使用 gzip 压缩…...

深入解析 Git Submodule:从基础到高级操作指南

深入解析 Git Submodule:从基础到高级操作指南 一、Git Submodule 是什么? git submodule 是 Git 提供的一个强大功能,允许在一个 Git 仓库(主仓库)中嵌入另一个独立的 Git 仓库(子模块)。主仓…...

2025-4-2 蓝桥杯刷题情况(分布式队列)

1.题目描述 小蓝最近学习了一种神奇的队列:分布式队列。简单来说,分布式队列包含 N 个节点(编号为0至N-1,其中0号为主节点),其中只有一个主节点,其余为副节点。 主/副节点中都各自维护着一个队列,当往分布式队列中添加…...

C/C++指针核心难点全解析:从内存模型到实战避坑指南

引言:指针为何被称为C/C的“灵魂”? 指针是C/C语言中最强大的工具之一,也是开发者通往底层编程的必经之路。它直接操作内存地址的能力,赋予了程序极高的灵活性和性能优势。然而,指针的复杂性也让无数初学者“折戟沉沙…...

ray.rllib-入门实践-12-2:在自定义policy中注册使用自定义model(给自定义model新增参数)

建议先看博客 ray.rllib-入门实践-12-1:在自定义policy中注册使用自定义model , 本博客与之区别在于可以给自定义的 model 新增自定义的参数,并通过 config.model["custom_model_config"] 传入自定义的新增参数。 环境配置&#xf…...

【Java中级】10章、内部类、局部内部类、匿名内部类、成员内部类、静态内部类的基本语法和细节讲解配套例题巩固理解【5】

❤️ 【内部类】干货满满,本章内容有点难理解,需要明白类的实例化,学完本篇文章你会对内部类有个清晰的认知 💕 内容涉及内部类的介绍、局部内部类、匿名内部类(重点)、成员内部类、静态内部类 🌈 跟着B站一位老师学习…...

swift-7-汇编分析闭包本质

一、汇编分析 fn1里面存放的东西 func testClosure2() {class Person {var age: Int 10}typealias Fn (Int) -> Intvar num 0func plus(_ i: Int) -> Int {num ireturn num}return plus} // 返回的plus和num形成了闭包var fn1 getFn()print(fn1(1)) // 1print(fn1(…...

Linux: 进程信号初识

目录 一 前言 二 信号的感性认识 三 信号处理常见方式 四 系统信号列表 五 信号的保存 六 信号的产生 1. 通过终端按键产生信号 2. 通过系统调用向进程发送信号 3. 硬件异常产生信号 4. 软件条件产生信号 一 前言 在Linux操作系统中,进程信号是一个非常重…...

python 项目怎么通过docker打包

python 项目怎么通过docker打包 1. 编写Dockerfile 在Python项目的根目录下创建一个名为 Dockerfile 的文件,其内容示例如下: # 使用Python基础镜像 FROM python:3.9-slim# 设置工作目录 WORKDIR /app# 将当前目录下的所有文件复制到工作目录 COPY . /app# 安装项目依赖 R…...

MySQL-- 函数(单行函数):数值函数, 字符串函数

目录 1.数值函数 2. 字符串函数 1.数值函数 ABS:绝对值 ; SIGN:数字正负,正返回1,负返回-1 , 0返回0 ; CEIL,CEILING:取数上面的数 ;FLOOR:取数下面的数 ; MOD:取余 #基本的操作 SELECT ABS(-123),ABS…...

CSS--解决float: right在空间不够时会自动往下移的问题

原文网址:CSS--解决float: right在空间不够时会自动往下移的问题-CSDN博客 简介 众所周知,float: right在空间不够时会自动往下移。那么怎样让它不要往下移呢?本文介绍解决方案。 需求 我想写一个无需列表,每个列表后边跟一个…...

深度学习 Deep Learning 第14章 自编码器

深度学习 Deep Learning 第14章 自编码器 内容概要 本章深入探讨了自编码器(Autoencoders),这是一种用于特征学习和降维的神经网络架构。自编码器通过编码器和解码器两个部分,将输入数据映射到一个内部表示(编码&…...

C++(匿名函数+继承+多态)

#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory>using namespace std;// 基类 Weapon class Weapon { protected:int atk; public:Weapon…...

软考中级网络工程师第十一章网络管理

11-1考点分析 11-2网络管理基础&#xff08;记忆&#xff09; 网络管理体系结构 网络管理五大功能域&#xff1a;故障管理、配置管理、计费管理、性能管理和安全管理。 助记&#xff1a; “安配能计障” 故障管理&#xff1a;尽快发现故障&#xff0c;找出故障原因&#x…...

创维E900V22C/E900V22D_S905L3(B)_安卓9.0_指示灯正常_线刷固件包

创维E900V22C&#xff0f;E900V22D_S905L3(B)_安卓9.0_指示灯正常_线刷固件包 线刷方法&#xff1a;&#xff08;新手参考借鉴一下&#xff09; 1、准备好一根双公头USB线刷刷机线&#xff0c;长度30-50CM长度最佳&#xff0c;同时准备一台电脑&#xff1b; 2、电脑上安装好刷…...

“京数青算“启新篇|北方算网与海东市数据局签署合作协议

近日&#xff0c;青海省海东市2025年“京数青算”推介会在北京召开。海东市委常委、副市长梁荣勃&#xff0c;海东市数据局局长安志忠出席会议&#xff0c;北方算网副总经理&#xff08;主持工作&#xff09;喻一鸣等60余家人工智能企业的代表参会。 梁荣勃在致辞中代表海东市…...

QML输入控件: Slider的高级外观定制(音视频控制条)

目录 引言相关阅读示例1&#xff1a;基础样式定制要点效果 示例2&#xff1a;音量控制滑块要点效果 示例3&#xff1a;视频进度条要点效果 解决问题总结工程下载 引言 在现代用户界面设计中&#xff0c;滑块控件(Slider)是一个不可或缺的交互元素。它不仅能让用户直观地进行数…...

密码学基础——古典密码学

目录 一、定义 特点&#xff1a; 二、发展阶段 三、代换密码 1.单表代换密码 1.1恺撒密码 1.2 移位变换 1.3 仿射变换 2.多表代换密码 维吉尼亚密码 四、置换密码 栅栏密码 一、定义 古典密码学是指在现代密码学出现之前&#xff0c;使用较为简单的数学方法和手工…...