无外网环境使用helm部署Falco

背景 在K8s集群中,希望引入Falco进行统一的集群操作审计 这就需要先安装Falco,借助json插件与k8saudit插件创建一个Webhook客户端,专用于接收API Server的操作审计数据 当前已有falco:0.44.0镜像,以及一个Falco的custom_values.yaml: driver: enabled: false collectors: enabled: false controller: kind: deployment services: - name: k8saudit-webhook type: NodePort ports: - port: 9765 protocol: TCP falco: rules_files: - /etc/falco/k8s_audit_rules.yaml - /etc/falco/rules.d plugins: - name: k8saudit library_path: /usr/share/falco/plugins/libk8saudit.so init_config: "" open_params: "http://:9765/k8s-audit" - name: json library_path: /usr/share/falco/plugins/libjson.so init_config: "" load_plugins: - k8saudit - json json_output: true json_include_output_property: true json_include_tags_property: true 关于格式 values文件的格式可参考:https://raw.githubusercontent.com/falcosecurity/charts/refs/heads/master/charts/falco/values.yaml 在机器可以访问外网的情况下,执行helm install falco falcosecurity/falco -n kube-audit -f custom_values.yaml即可将Falco部署到集群 但我们的集群无法访问外网,首先拉取不到Chart,其次也拉取不到falcoctl以及两个插件,甚至连插件的index文件都无法获取 因此,需要考虑离线安装Falco 手动下载Chart 执行: wget https://github.com/falcosecurity/charts/releases/download/falco-9.0.0/falco-9.0.0.tgz 即可获取falco-9.0.0.tgzChart文件,如此一来,Chart的本地化解决 falcoctl离线安装 在Pod启动时,会尝试拉取falcoctl容器镜像,它会被自动配置为Falco Pod的一个Init Container,用于管理安全规则Rules、插件Plugins ...

June 1, 2026

Keycloak自定义条件执行器开发经验

介绍 Keycloak中的自定义SPI种类有很多,在设计认证流时,可添加三种类型: 执行器(Execution) 在主流程中标签为execution;在子流程中标签为step 条件(Condition) 标签为condition 子流程(Sub-flow) 标签为flow 执行器用于直接执行某项认证,例如要求用户输入账户名密码、要求用户进行TOTP认证等,通常包括一个或多个用于认证的前端页面以与用户交互 条件用于根据某项信息进行决策判断,决定是否执行所在的流程或子流程,一般不包括前端页面(因为只需要与系统内信息交互,不会参与用户操作过程) 子流程用于划分更精细的认证流程,通常与条件共同构成认证流的某一个条件分支 接下来开发一个最简单的自定义条件类型SPI,作用是负责判断当前上下文中的属性registeringDevice的值是否为true,如果为true,则条件成立,否则不成立 开发 不同于开发自定义认证器SPI需要继承、实现多个类或接口,自定义条件SPI只需要一个实现了ConditionalAuthenticator接口的类以及相应地实现了ConditionalAuthenticatorFactory接口的工厂类即可 编写RegisterDeviceConditionAuthenticator类,实现ConditionalAuthenticator接口: public class RegisterDeviceConditionAuthenticator implements ConditionalAuthenticator { @Override public boolean matchCondition(AuthenticationFlowContext authenticationFlowContext) { String registeringDevice = authenticationFlowContext.getAuthenticationSession().getClientNote("registeringDevice"); return "true".equals(registeringDevice); } @Override public void action(AuthenticationFlowContext authenticationFlowContext) {} @Override public boolean requiresUser() { return false; } @Override public void setRequiredActions(KeycloakSession keycloakSession, RealmModel realmModel, UserModel userModel) {} @Override public void close() {} } 这个类唯一需要关注的就是matchCondition()方法,这个方法定义了【何种条件下条件成立】,在这里表现为读取registeringDevice属性并返回是否为"true" 接下来编写RegisterDeviceConditionAuthenticatorFactory类,实现ConditionalAuthenticatorFactory接口: public class RegisterDeviceConditionAuthenticatorFactory implements ConditionalAuthenticatorFactory { public static final String PROVIDER_ID = "register-device-condition"; private static final ConditionalAuthenticator SINGLETON = new RegisterDeviceConditionAuthenticator(); private static AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { AuthenticationExecutionModel.Requirement.REQUIRED, AuthenticationExecutionModel.Requirement.DISABLED }; @Override public String getDisplayType() { return "Condition - 注册设备时触发"; } @Override public boolean isConfigurable() { return false; } @Override public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { return REQUIREMENT_CHOICES; } @Override public boolean isUserSetupAllowed() { return false; } @Override public String getHelpText() { return "只有在注册设备流程中才会执行子认证器"; } @Override public List<ProviderConfigProperty> getConfigProperties() { return null; } @Override public void init(Config.Scope scope) {} @Override public void postInit(KeycloakSessionFactory keycloakSessionFactory) {} @Override public void close() {} @Override public String getId() { return PROVIDER_ID; } // create()实际上是执行了getSingleton(),因此重写create()与重写getSingleton()是等价的 @Override public ConditionalAuthenticator getSingleton() { return SINGLETON; } } 这个工厂类定义了该条件SPI将如何展示于Keycloak系统中,并设置了“必需”、“禁用”两种可选选项,用于开关功能 ...

September 3, 2025

IDEA远程调试Keycloak自定义SPI

在基于Keycloak开发调试自定义SPI时,为了使其运行,通常需要: 手动将项目打包为jar文件 将其放入Keycloak的/providers目录中 在命令行重启Keycloak服务 对于需要观察运行状态、乃至打断点的调试来说十分不便 考虑使用JVM远程调试 + HotSwap实现对Keycloak的实时调试 JVM配置 首先需要让JVM在5005端口上监听调试请求,所以在终端设置参数(以Windows为例): set JAVA_OPTS_APPEND=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 然后在同一个终端下加载jar包、运行服务: bin\kc.bat start-dev 注意 使用set命令设置的环境变量仅在当前终端窗口生效,所以需要在同一个终端下运行以上两条命令;或者可以手动在系统设置中配置环境变量,然后打开一个新终端直接运行Keycloak 服务启动后终端显示大概如下: IDEA配置 打开IDEA,在右上角找到调试下拉框(就是正常运行、调试代码的部分),进入编辑配置页面后点击页面左上角加号添加新调试,在左侧选择添加【远程JVM调试】 接下来配置该调试的各参数,名称随意,注意主机和端口要正确填写: 完成后点击调试按钮,即可看到IDEA下方调试栏中提示:已连接到地址为 ''localhost:5005',传输: '套接字'' 的目标虚拟机,则环境配置成功 HotSwap 在已连接的情况下,对代码进行修改时,代码编辑框体的右上角会出现Code changed提示与按钮,点击后即可实现JVM对class的热更新 如此一来,每次修改代码、需要调试时,无需重新打包、导入自定义SPI的繁复操作,点击按钮即可自动编译项目、更新JVM中运行的class文件 局限 由于HotSwap只能对编译生成的class文件热更新,所以本文章的方法并不能对前端FTL文件进行实时调试,每当修改了FTL文件时,仍然需要重新打包并导入Keycloak;另外,HotSwap也不支持对类名、类增减以及方法增减的热更新

August 21, 2025

使用VSCode解决fork项目的同步冲突

在Github上Fork了一个iptv-api的项目,设置自动获取信息的Action实现了对IPTV源的每日更新,但有时上游仓库会对项目功能作更新或修复,这时就需要将Fork仓库与上游仓库同步,此时就可能出现冲突 Github无法在线解决冲突,这里使用VSCode解决 首先打开VScode,进入Fork项目的目录中,确保VScode已识别本地仓库且已添加上游仓库,然后新建终端执行: git fetch upstream 接着输入git branch确保正在需要同步的分支上,在本例中,只存在一个分支master;如果存在多个分支,则使用git checkout <branch>切换即可 执行合并: git merge upstream/master 执行后,VSCode左侧导航栏就会提示存在冲突的文件,可以鼠标点击选择是否保留先前内容,选择完成后保存、提交并同步即可,流程与正常使用VSCode执行Git操作一致

August 15, 2025

将Java项目打包为可执行文件

本实例的Java工程构建了一个简单的服务器,监听本地的12345端口,当接收到GET请求:/get_cpuid时,返回当前运行终端的CPUID信息 整个流程分为两部分: 工程打包为jar文件 jar文件转换为exe安装程序,安装后得到exe可执行程序 在打包为jar之前需要指定主类,Maven设置: <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>org.example.LocalHardwareService</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> 执行mvn package后会打包为一个fat jar,文件名GetDeviceInfo-1.0-SNAPSHOT-shaded.jar 警告 若不使用fat jar,则安装的exe会提示启动JVM失败 执行以下jpackage命令: jpackage --input target/ --name LocalHWService --main-jar GetDeviceInfo-1.0-SNAPSHOT-shaded.jar --main-class org.example.LocalHardwareService --type exe --vendor "FICN" --description "Local Hardware Info Service" input:输入目录。因为jar文件是被打包存储于项目的/target目录中的; main-jar:jar文件名; main-class:主类名; vendor:发行公司名; description:文件描述,会显示在任务管理器中 说明 一般来说,vendor和description属性是无需特别指定的,但由于执行这jpackage指令会使用WiX,而我所安装的WiX(v3.14.1)的这两个属性默认会使用非ASCII字符,这就导致了jpackage命令报错,所以需要手动指定这两个属性,保证是纯英文 命令完成后在当前目录生成LocalHWService-1.0.exe文件,这个文件并不能直接运行服务,而是一个安装程序 双击打开后自动安装,一般会安装到C:\Program Files中,进入子目录\LocalHWService后,可以看到文件: LocalHWService.exe就是服务文件了,双击运行,打开任务管理器可以看到其在后台正常运行: 在浏览器中进行测试,此时请求正常得到响应:

August 5, 2025