AWS-WAF-CDN基于速率rate的永久黑名单方案(基于lambda实现)

news2024/11/26 11:44:00

参考方案(有坑), 所以产生了这篇博客: 点击跳转

1. 部署waf (有则跳过)

在这里插入图片描述
必须存在一个rate速率规则,后面的方案堆栈要用

新建rate速率规则

在这里插入图片描述
在这里插入图片描述
关联cdn资源
在这里插入图片描述

2.部署堆栈 (美国东部 (弗吉尼亚北部 us-east-1)

1 .堆栈文件获取方式:

1.公开s3桶调用:https://actwill-cloudformation-template.s3.amazonaws.com/waf-block-rate-ip/waf_block_rate_ip_20231208.template

2.也可以手动选择复制保存

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  Scope:
    Type: String
    Description: Enter WebACL Scope CLOUDFRONT or REGIONAL
    AllowedValues: [REGIONAL, CLOUDFRONT]
  WebACLName:
    Type: String
    Description: Enter WebACL name
  WebACLId:
    Type: String
    Description: Enter WebACL ID
  RateBasedRuleName:
    Type: String
    Description: Enter Rate Based Rule Name
  CustomBlockPeriod:
    Type: Number
    Description: Enter custom block period for blocking the IP addresses in minutes. Minimum is 06 minutes
    MinValue: 6

Resources:
  CustomRBRLogBucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: !Join
      - "-"
      - - "custom-rbr-log-bucket"
        - !Select
          - 0
          - !Split
            - "-"
            - !Select
              - 2
              - !Split
                - "/"
                - !Ref "AWS::StackId"
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration: 
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      LoggingConfiguration: 
        DestinationBucketName: !Ref AccessLoggingBucket

  CustomRBRLogBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket:
        Ref: CustomRBRLogBucket
      PolicyDocument:
        Statement:
        - Action: "s3:*"
          Condition:
            Bool:
              aws:SecureTransport: 'false'
          Effect: Deny
          Principal: "*"
          Resource:
            - !GetAtt CustomRBRLogBucket.Arn
            - !Join ["/", [!GetAtt CustomRBRLogBucket.Arn, "*"]]
          Sid: HttpsOnly
        Version: '2012-10-17'

  AccessLoggingBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W35
            reason: "This bucket is an access logging bucket for another bucket and does not require access logging to be configured for it."    

  AccessLoggingBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket:
        Ref: AccessLoggingBucket
      PolicyDocument:
        Statement:
        - Action: "s3:*"
          Condition:
            Bool:
              aws:SecureTransport: 'false'
          Effect: Deny
          Principal: "*"
          Resource:
            - !GetAtt AccessLoggingBucket.Arn
            - !Join ["/", [!GetAtt AccessLoggingBucket.Arn, "*"]]
          Sid: HttpsOnly
        Version: '2012-10-17'

  IPv4IPset:
    Type: "AWS::WAFv2::IPSet"
    Properties:
      Name: !Join
      - "-"
      - - "IPv4-IPset"
        - !Select
          - 0
          - !Split
            - "-"
            - !Select
              - 2
              - !Split
                - "/"
                - !Ref "AWS::StackId"
      Scope: !Ref Scope
      Description: "IPv4 IP set for custom rate based block rule"
      IPAddressVersion: "IPV4"
      Addresses: []

  IPv6IPset:
    Type: "AWS::WAFv2::IPSet"
    Properties:
      Name: !Join
      - "-"
      - - "IPv6-IPset"
        - !Select
          - 0
          - !Split
            - "-"
            - !Select
              - 2
              - !Split
                - "/"
                - !Ref "AWS::StackId"
      Scope: !Ref Scope
      Description: "IPv6 IP set for custom rate based block rule"
      IPAddressVersion: "IPV6"
      Addresses: []

  CustomRBRLambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      FunctionName: !Join
      - "-"
      - - "CustomRBRLambdaFunction"
        - !Select
          - 0
          - !Split
            - "-"
            - !Select
              - 2
              - !Split
                - "/"
                - !Ref "AWS::StackId"
      Description: Lambda function containing the logic for custom RBR
      Handler: index.lambda_handler
      Role: !GetAtt LambdaRole.Arn
      Runtime: python3.9
      Environment:
        Variables:
          SCOPE: !Ref Scope
          WEB_ACL_NAME: !Ref WebACLName
          WEB_ACL_ID: !Ref WebACLId
          RATE_BASED_RULE_NAME: !Ref RateBasedRuleName
          CUSTOM_BLOCK_PERIOD: !Ref CustomBlockPeriod
          CONFIG_LOG_BUCKET: !Ref CustomRBRLogBucket
          CONFIG_LOG_KEY: blocked_ips_list.json
          IP_SET_ID_CUSTOM_V4: !GetAtt IPv4IPset.Id
          IP_SET_NAME_CUSTOM_V4: !Select
                                    - "0"
                                    - !Split [ "|" , Ref: IPv4IPset]
          IP_SET_ID_CUSTOM_V6: !GetAtt IPv6IPset.Id
          IP_SET_NAME_CUSTOM_V6: !Select
                                    - "0"
                                    - !Split [ "|" , Ref: IPv6IPset]
      Code:
        ZipFile: |
          import json
          import boto3
          import logging
          import datetime
          import os
          
          wafv2_client = boto3.client('wafv2')
          s3_client = boto3.client('s3')
          
          def update_custom_ipset_and_config(log, latest_ipv4_blocked_list,
                                             latest_ipv6_blocked_list):
              try:
                  # update the custom v4 IP set
                  ipv4_lock_token = get_lock_token(
                      log, wafv2_client,
                      os.getenv('IP_SET_ID_CUSTOM_V4'),
                      os.getenv('IP_SET_NAME_CUSTOM_V4')
                  )
                  update_ip_set(
                      log, wafv2_client,
                      os.getenv('IP_SET_ID_CUSTOM_V4'),
                      list(latest_ipv4_blocked_list.keys()),
                      ipv4_lock_token,
                      os.getenv('IP_SET_NAME_CUSTOM_V4')
                  )
          
                  # update the custom v6 IP set
                  ipv6_lock_token = get_lock_token(
                      log, wafv2_client,
                      os.getenv('IP_SET_ID_CUSTOM_V6'),
                      os.getenv('IP_SET_NAME_CUSTOM_V6')
                  )
                  update_ip_set(
                      log, wafv2_client,
                      os.getenv('IP_SET_ID_CUSTOM_V6'),
                      list(latest_ipv6_blocked_list.keys()),
                      ipv6_lock_token,
                      os.getenv('IP_SET_NAME_CUSTOM_V6')
                  )
              except Exception as e:
                  # log error message
                  log.error("[update_custom_ipset_and_config] "
                            "Error updating custom ipset.")
                  raise e
          
              try:
                  # create json object of the latest custom config
                  latest_custom_config = {
                      'IPv4': latest_ipv4_blocked_list,
                      'IPv6': latest_ipv6_blocked_list
                  }
                  byte_latest_custom_config = json.dumps(latest_custom_config).encode()
          
                  # upload the config to s3
                  s3_client.put_object(
                      Bucket=os.getenv('CONFIG_LOG_BUCKET'),
                      Body=byte_latest_custom_config,
                      Key=os.getenv('CONFIG_LOG_KEY')
                  )
              except Exception as e:
                  # log error message
                  log.error("[update_custom_ipset_and_config] "
                            "Error uploading config to S3.")
                  raise e
          
          
          def get_lock_token(log, wafv2_client, ip_set_id, name):
              try:
                  ipv4_get_response = wafv2_client.get_ip_set(
                      Scope=os.getenv('SCOPE'),
                      Name=name,
                      Id=ip_set_id
                  )
                  return ipv4_get_response['LockToken']
              except Exception as e:
                  log.error(f"Error in get_lock_token: {e}")
                  raise
          
          
          def update_ip_set(log, wafv2_client, ip_set_id, addresses,
                            lock_token, name):
              try:
                  wafv2_client.update_ip_set(
                      Scope=os.getenv('SCOPE'),
                      Name=name,
                      Id=ip_set_id,
                      Description='Last Update: ' +
                                  datetime.datetime.now(datetime.timezone.utc).strftime(
                                                               "%Y-%m-%d %H:%M:%S %Z%z"),
                      Addresses=addresses,
                      LockToken=lock_token
                  )
              except Exception as e:
                  log.error("Error in update_ip_set: {}".format(e))
                  raise
          
          
          def sync_ip_from_rbr_to_custom_ipset(log, rbr_managed_ip_list,
                                               custom_managed_ip_config):
              # Get the current timestamp in UTC format
              utc_now_timestamp = datetime.datetime.now(
                  datetime.timezone.utc)
              # Convert the timestamp to string
              utc_now_timestamp_str = utc_now_timestamp.strftime(
                  "%Y-%m-%d %H:%M:%S %Z%z")
          
              # Iterate over the managed IPs in the RBR list
              for managed_ip in rbr_managed_ip_list:
                  # If the IP is already in the custom IP config
                  if managed_ip in custom_managed_ip_config.keys():
                      # Get the timestamp when the IP was blocked in UTC format
                      utc_blocked_at = datetime.datetime.strptime(
                          custom_managed_ip_config[managed_ip],
                          "%Y-%m-%d %H:%M:%S %Z%z").astimezone(
                          datetime.timezone.utc)
                      # Calculate the difference in minutes between now and when the IP
                      # was blocked
                      total_diff_min = ((utc_now_timestamp - utc_blocked_at)
                                        .total_seconds()) / 60
                                        
                      # If the difference is greater than block period, update the timestamp
                      if round(total_diff_min) >= int(os.getenv('CUSTOM_BLOCK_PERIOD')):
                          custom_managed_ip_config[managed_ip] = utc_now_timestamp_str
                  # If the IP is not in the custom IP config, add it with the current
                  # timestamp
                  else:
                      custom_managed_ip_config[managed_ip] = utc_now_timestamp_str
          
              # Create a new dictionary to store the latest blocked IPs
              latest_ip_blocked_list = {}
              
              # Iterate over the custom IP config
              for blocked_ip, blocked_at_str in custom_managed_ip_config.items():
                  # Get the timestamp when the IP was blocked in UTC format
                  utc_blocked_at = datetime.datetime.strptime(
                      custom_managed_ip_config[blocked_ip],
                      "%Y-%m-%d %H:%M:%S %Z%z").astimezone(datetime.timezone.utc)
                  # Calculate the difference in minutes between now and when the IP
                  # was blocked
                  total_diff_min = ((utc_now_timestamp - utc_blocked_at)
                                    .total_seconds()) / 60
                  # If the difference is less than the custom block period
                  #then add it to the latest blocked IPs list
                  if round(total_diff_min) < int(os.getenv('CUSTOM_BLOCK_PERIOD')):
                      latest_ip_blocked_list[blocked_ip] = blocked_at_str
  
              return latest_ip_blocked_list
          
          
          def get_custom_config_file(log):
              try:
                  # Get the custom config file from S3
                  s3_response = s3_client.get_object(
                      Bucket=os.getenv('CONFIG_LOG_BUCKET'),
                      Key=os.getenv('CONFIG_LOG_KEY')
                  )
                  # Load the custom config file as a JSON object
                  custom_managed_ip_config = json.loads(
                      s3_response['Body'].read()
                  )
              except Exception as e:
                  log.error("[get_custom_config_file] Error to get the custom config "
                            "file from S3")
                  log.error(e)
                  # If there is an error, return an empty config
                  custom_managed_ip_config = {'IPv4': {}, 'IPv6': {}}
          
              return custom_managed_ip_config
          
          
          def get_rbr_managed_ip_list(log):
              try:       
                  # Get the list of IPs blocked by the rate based rule
                  wafv2_response = wafv2_client.get_rate_based_statement_managed_keys(
                      Scope=os.getenv('SCOPE'),
                      WebACLName=os.getenv('WEB_ACL_NAME'),
                      WebACLId=os.getenv('WEB_ACL_ID'),
                      RuleName=os.getenv('RATE_BASED_RULE_NAME')
                  )
          
                  return wafv2_response
              except Exception as e:
                  log.error("[get_rbr_managed_ip_list] "
                            "Error to get the list of IP blocked by rate based rule")
                  log.error(e)
                  # If there is an error, raise the exception
                  raise e
          
          
          def lambda_handler(event, context):
              log = logging.getLogger()
          
              try:
                  # Set Log Level
                  log.setLevel(logging.ERROR)
          
                  # Get the list of IP blocked by rate based rule
                  rbr_managed_list = get_rbr_managed_ip_list(log)
          
                  # Get custom config file from S3
                  custom_managed_ip_config = get_custom_config_file(log)
          
                  # Update IP from rate based rule list to custom list
                  latest_ipv4_blocked_list = sync_ip_from_rbr_to_custom_ipset(
                      log, rbr_managed_list['ManagedKeysIPV4']['Addresses'],
                      custom_managed_ip_config['IPv4'])
                  latest_ipv6_blocked_list = sync_ip_from_rbr_to_custom_ipset(
                      log, rbr_managed_list['ManagedKeysIPV6']['Addresses'],
                      custom_managed_ip_config['IPv6'])
          
                  # Update latest blocked list to S3 and WAF IPset
                  update_custom_ipset_and_config(log, latest_ipv4_blocked_list,
                                                 latest_ipv6_blocked_list)
          
                  return {
                      'statusCode': 200,
                      'body': json.dumps('Update Success!')
                  }
              except Exception as e:
                  log.error(e)
                  return {
                      'statusCode': 500,
                      'body': e
                  }
      Timeout: 10
    Metadata:
      cfn_nag:
        rules_to_suppress:
        - id: W89
          reason: There is no need to run this lambda in a VPC
        - id: W92
          reason: There is no need for Reserved Concurrency

  LambdaRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:

        - Effect: "Allow"
          Principal:
            Service:
              - "lambda.amazonaws.com"
          Action: "sts:AssumeRole"

      ManagedPolicyArns:
          - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

      Policies:
          - PolicyName: !Join
            - "-"
            - - "LambdaRolePolicy"
              - !Select
                - 0
                - !Split
                  - "-"
                  - !Select
                    - 2
                    - !Split
                      - "/"
                      - !Ref "AWS::StackId"

            PolicyDocument:
              Version: "2012-10-17"
              Statement:
              - Sid: "S3BucketPermissions"
                Effect: "Allow"
                Action:
                - "s3:PutObject"
                - "s3:GetObject"
                Resource:
                  - !Sub 'arn:${AWS::Partition}:s3:::${CustomRBRLogBucket}/blocked_ips_list.json'
              - Sid: "WAFIPSetPermissions"
                Effect: "Allow"
                Action:
                - "wafv2:GetIPSet"
                - "wafv2:UpdateIPSet"
                Resource:
                  - !GetAtt IPv6IPset.Arn
                  - !GetAtt IPv4IPset.Arn
              - Sid: "WAFRBRPermissions"
                Effect: "Allow"
                Action: "wafv2:GetRateBasedStatementManagedKeys"
                Resource: !Sub
                  - 'arn:${AWS::Partition}:wafv2:${AWS::Region}:${AWS::AccountId}:${WebACLSope}/webacl/${WebACLName}/${WebACLId}'
                  - WebACLSope: !If [IsRegional, "regional", "global"]


  EventBridgeRule:
      Type: "AWS::Events::Rule"
      Properties:
        Name: !Join
        - "-"
        - - "EventBridgeRule"
          - !Select
            - 0
            - !Split
              - "-"
              - !Select
                - 2
                - !Split
                  - "/"
                  - !Ref "AWS::StackId"
        ScheduleExpression: "rate(1 minute)"
        State: "ENABLED"
        Targets:
          - Id: "CustomRBRLambdaFunction"
            Arn: !GetAtt CustomRBRLambdaFunction.Arn

  LambdaPermissionForEventBridge:
    Type: "AWS::Lambda::Permission"
    Properties:
      FunctionName: !Ref CustomRBRLambdaFunction
      Action: "lambda:InvokeFunction"
      Principal: "events.amazonaws.com"
      SourceArn: !GetAtt EventBridgeRule.Arn

Outputs:
  IPv4IPsetName:
    Description: IPv4 IPSet for custom rate based block rule
    Value: !Select
              - "0"
              - !Split [ "|" , Ref: IPv4IPset]
  IPv6IPsetName:
    Description: IPv6 IPSet for custom rate based block rule
    Value: !Select
              - "0"
              - !Split [ "|" , Ref: IPv6IPset]

Conditions:
  IsRegional:
    !Equals [!Ref Scope, "REGIONAL"]

2. 新建堆栈

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
等待创建完成,查看相关参数资源
在这里插入图片描述
在这里插入图片描述

3. 回到waf确认,无误后开始测试

在这里插入图片描述

发现已经创建对应的ip规则集

在这里插入图片描述

添加到对应的waf中拒绝此ip集

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

开始测试

找一个终端,这里我使用cloudshell
使用我编写的脚本进行测试
在这里插入图片描述

$ cat waf.sh 

#!/bin/bash
while true; do 
    curl -I  http://xxxxxx.cloudfront.net/xxxx.png
    sleep 0.5
done


##开始测试
# sh waf.sh 

在这里插入图片描述
查看是否在ip黑名单中
在这里插入图片描述
cdn备用域名测试
在这里插入图片描述
说明方案生效(从ip集中删除即可恢复访问)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1320924.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安卓小练习-校园闲置交易APP(SQLite+SimpleCursorAdapter适配器)

环境&#xff1a; SDK&#xff1a;34 JDK&#xff1a;20.0.2 编写工具&#xff1a;Android Studio 2022.3.1 整体效果&#xff08;视频演示&#xff09;&#xff1a; 小练习-闲置社区APP演示视频-CSDN直播 部分效果截图&#xff1a; 整体工作流程&#xff1a; 1.用户登录&…

【基础篇】1.2 认识STM32(二)

3.3 VREF/VREF-引脚 VREF和VREF-是STM32中用于提供参考电压的引脚。如下图&#xff1a; VREF引脚可以连接一个单独的外部参考电压&#xff0c;范围在2.0V&#xff5e;VDDA&#xff0c;但不能超过VDDA&#xff0c;否则就超过了模拟器件的最大供电电压。在100引脚的封装中&#…

数据可视化---双Y轴折线图比较

内容导航 类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统…

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)十五:基础数据模块相关功能实现

一、本章内容 本章使用已实现的公共组件实现系统管理中的基础数据中的验证码管理、消息管理等功能。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 3.1 B站视频地址: 基于VUE3+Layui从头搭建通用后台管理系统合集-验证码功能实现 3.2 西瓜…

视频推拉流EasyDSS互联网直播/点播平台构建户外无人机航拍直播解决方案

一、背景分析 近几年&#xff0c;国内无人机市场随着航拍等业务走进大众&#xff0c;出现爆发式增长。无人机除了在民用方面的应用越来越多&#xff0c;在其他领域也已经开始广泛应用&#xff0c;比如公共安全、应急搜救、农林、环保、交通 、通信、气象、影视航拍等。无人机使…

Leetcode—746.使用最小花费爬楼梯【简单】

2023每日刷题&#xff08;六十一&#xff09; Leetcode—746.使用最小花费爬楼梯 算法思想 参考灵神 实现代码 class Solution { public:int minCostClimbingStairs(vector<int>& cost) {int n cost.size();vector<int> f(n 1);for(int i 2; i < n;…

DY某音视频评论区采集 评论数据抓取

某音用户评论和ID的采集方法主要使用burpsuite火狐浏览器抓包分析请求接口 火狐浏览器设置走代理模式&#xff1a;IP地址为本机127.0.0.1 端口8080 \/&#xff1a;jeomoo168 burpsuite->代理->HTTP历史记录那可以看到请求接口https://www.douyin.com/aweme/v1/web/com…

JDK bug:ciObjectFactory::create_new_metadata

文章目录 1、问题2.详细日志3.JDK&#xff1a;bug最终bug链接&#xff1a; 京东遇到过类似bug各位大佬如果有更详细的解答可以留言。 1、问题 Problematic frame: V [libjvm.so0x438067] ciObjectFactory::create_new_metadata(Metadata*)0x327 关键字还是ciObjectFactory::cr…

Ubuntu 18.04配置NFS服务器以及配置时遇到NFS问题

1.安装相关软件 sudo apt-get install nfs-kernel-server sudo apt-get install nfs-common 2.配置共享目录 2.1修改exports文件 sudo vi /etc/exports在最后添加如下并保存退出 /home/xiaowu/nfs 192.168.31*(rw,sync,no_root_squash,no_subtree_check) /home/xiaowu/nfs…

【论文阅读笔记】Pre-trained Universal Medical Image Transformer

Luo L, Chen X, Tang B, et al. Pre-trained Universal Medical Image Transformer[J]. arXiv preprint arXiv:2312.07630, 2023.【代码开源】 【论文概述】 本文介绍了一种名为“预训练通用医学图像变换器&#xff08;Pre-trained Universal Medical Image Transformer&…

nodejs+vue+微信小程序+python+PHP国漫推荐系统-计算机毕业设计推荐

使得本系统的设计实现具有可使用的价。做出一个实用性好的国漫推荐系统&#xff0c;使其能满足用户的需求&#xff0c;并可以让用户更方便快捷地国漫推荐。这个系统的设计主要包括系统页面的设计和方便用户互动的后端数据库&#xff0c;在开发后需要良好的数据处理能力、友好的…

ElementUI,修改el-select下拉框的样式

在使用到el-select组件中设置:popper-append-to-body“false” <el-selectv-model"value":popper-append-to-body"false"placeholder"请选择" ><el-optionv-for"item in options":key"item.value":label"ite…

农业物联网市场调研:2023年市场现状及发展机遇

近年来数字农业发展迅猛&#xff0c;不仅对我国农业经济快速发展产生了积极影响&#xff0c;而且已经成为全球发展最快的数字农业产业之一。数字农业未来的发展前景虽然非常富有吸引力。数字经济快速发展背景下&#xff0c;“数字农业”应运而生。 何谓农业物联网&#xff1f;农…

Android Studio设置android:background 属性背景颜色

除了默认的颜色之外都要自己添加。 添加颜色的操作步骤&#xff1a; 打开res文件夹&#xff0c;找values&#xff0c;里面有个colors.xml的文件。然后在里面定义一些颜色。 完成

持续集成交付CICD:Jenkins使用GitLab共享库实现前端项目镜像构建

目录 一、实验 1. GitLab修改项目文件与Harbor环境确认 2.Jenkins使用GitLab共享库实现前端项目镜像构建 3.优化CI流水线封装Harbor账户密码 4.Jenkins再次使用GitLab共享库实现前端项目镜像构建 一、实验 1. GitLab修改项目文件与Harbor环境确认 &#xff08;1&#xf…

Day64力扣打卡

打卡记录 方格取数&#xff08;线性DP&#xff09; import sys input sys.stdin.readline 输入样例&#xff1a; 8 2 3 13 2 6 6 3 5 7 4 4 14 5 2 21 5 6 4 6 3 15 7 2 14 0 0 0 输出样例&#xff1a; 67 n int(input()) w [[0] * (n 1) for _ in range(n 1)] while Tru…

三大主流前端框架介绍

在前端项目中&#xff0c;可以借助某些框架&#xff08;如React、Vue、Angular等&#xff09;来实现组件化开发&#xff0c;使代码更容易复用。此时&#xff0c;一个网页不再是由一个个独立的HTML、CSS和JavaScript文件组成&#xff0c;而是按照组件的思想将网页划分成一个个组…

Android-----AndroidManifests.xml 之meta-data

一、概念 meta-data&#xff1a;元数据、文件元数据。主要用来定义一些组件相关的配置值。 metadata是一组供父组件使用的名值对&#xff08;name-value pair&#xff09;&#xff0c;一个组件元素可以包含任意数量的meta-data子元素。这些子元素的值存放在一个 Bundle 对象中…

Qt-QTransform介绍与使用

QTransform是一个用于二维坐标系转换的类。我们知道Qt的坐标系是左上角为原点&#xff0c;x轴向右&#xff0c;y轴向下&#xff0c;屏幕上每个像素代表一个单位&#xff0c;那么&#xff0c;如果我们想要在屏幕上建立自己的坐标系用于绘制&#xff0c;就需要借助QTransform。 …

分布式链路追踪 —— 基于Dubbo的traceId追踪传递

文章目录 原文链接RpcContext 上下文对象Dubbo 过滤器&#xff08;Filter&#xff09;对象基于Dubbo的traceId追踪传递实现 原文链接 RpcContext 上下文对象 在实现 Dubbo 调用之间的链路跟踪之前&#xff0c;先简单了解 RpcContext 上下文对象和 Filter 过滤器对象&#xff…