Skip to content

Commit

Permalink
Merge pull request #9543 from fcfang123/issue-9414
Browse files Browse the repository at this point in the history
feat:接入审计中心 #9414
  • Loading branch information
bkci-bot authored Nov 20, 2023
2 parents 9dfcfb0 + b5ee66d commit 45dee17
Show file tree
Hide file tree
Showing 63 changed files with 2,226 additions and 104 deletions.
3 changes: 2 additions & 1 deletion scripts/bkenv.properties
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,8 @@ BK_CI_OPENAPI_API_PUB_OUTER=
BK_CI_OPENAPI_API_AUTH=true
# BK_CI_OPENAPI_VERIFY_PROJECT 在 blueking api filter 中使用,是否开启projectId强校验。
BK_CI_OPENAPI_VERIFY_PROJECT=false

# 是否开启审计,默认不开启
BK_CI_AUDIT_ENABLED=false

##########
# 4-微服务依赖
Expand Down
4 changes: 2 additions & 2 deletions src/backend/ci/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ apply(plugin = "org.owasp.dependencycheck")

allprojects {
apply(plugin = "com.tencent.devops.boot")

// 包路径
group = "com.tencent.bk.devops.ci"
// 版本
version = (System.getProperty("ci_version") ?: "1.9.0") +
if (System.getProperty("snapshot") == "true") "-SNAPSHOT" else ""
if (System.getProperty("snapshot") == "true") "-SNAPSHOT" else ""

// 加载boot的插件
if (name.startsWith("boot-")) {
Expand Down Expand Up @@ -126,6 +125,7 @@ allprojects {
entry("org.eclipse.jgit.ssh.jsch")
}
dependency("com.tencent.bk.sdk:iam-java-sdk:${Versions.iam}")
dependency("com.tencent.bk.sdk:spring-boot-bk-audit-starter:${Versions.audit}")
dependency("com.jakewharton:disklrucache:${Versions.disklrucache}")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ object Versions {
const val jgit = "5.13.1.202206130422-r"
const val iam = "1.0.0"
const val disklrucache = "2.0.2"
const val audit = "1.0.8"
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies {
api(project(":core:common:common-archive"))
api(project(":core:common:common-db"))
api(project(":core:common:common-auth:common-auth-api"))
api(project(":core:common:common-audit"))
api(project(":core:artifactory:api-artifactory"))
api(project(":core:artifactory:model-artifactory"))
api(project(":core:project:api-project"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ const val LOCALE_LANGUAGE = "BK_CI_LOCALE_LANGUAGE" // locale国际化语言信
const val DEFAULT_LOCALE_LANGUAGE = "zh_CN" // 默认语言信息
const val REQUEST_CHANNEL = "BK_CI_REQUEST_CHANNEL" // 请求渠道
const val API_PERMISSION = "BK_CI_API_PERMISSION" // 请求API权限
const val REQUEST_IP = "X-Forwarded-For" // 请求IP
const val BK_CREATE = "bkCreate" // 创建
const val BK_REVISE = "bkRevise" // 修改

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ enum class RequestChannelTypeEnum {
SERVICE,
BUILD,
OP,
OPEN
OPEN,
API
}
4 changes: 4 additions & 0 deletions src/backend/ci/core/common/common-audit/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies {
api("com.tencent.bk.sdk:spring-boot-bk-audit-starter")
api(project(":core:common:common-web"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.tencent.devops.common.audit

import com.tencent.bk.audit.constants.AuditAttributeNames.INSTANCE_ID
import com.tencent.bk.audit.constants.AuditAttributeNames.INSTANCE_NAME

@Suppress("MaxLineLength")
object ActionAuditContent {
private const val CONTENT_TEMPLATE = "[{{$INSTANCE_NAME}}]({{$INSTANCE_ID}})"
private const val PROJECT_CODE_CONTENT_TEMPLATE = "[{{@PROJECT_CODE}}]"
const val PROJECT_CODE_TEMPLATE = "@PROJECT_CODE"
const val BUILD_ID_TEMPLATE = "@BUILD_ID"
const val ASSIGNS_TEMPLATE = "@ASSIGNS"

// 项目
const val PROJECT_MANAGE_RESTORE_PIPELINE_CONTENT = "restore pipeline $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"

// 流水线
const val PIPELINE_VIEW_CONTENT = "get pipeline info $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_SHARE_CONTENT = "share pipeline $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_CREATE_CONTENT = "create pipeline $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_LIST_CONTENT = "list pipeline $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_DOWNLOAD_CONTENT = "download pipeline $CONTENT_TEMPLATE buildId [{{$BUILD_ID_TEMPLATE}}] " +
"in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_EDIT_CONTENT = "update pipeline $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_EDIT_SAVE_SETTING_CONTENT = "save pipeline setting $CONTENT_TEMPLATE " +
"in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_EDIT_EXPORT_PIPELINE_CONTENT = "export pipeline $CONTENT_TEMPLATE " +
"in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_EDIT_BIND_PIPELINE_CALLBACK_CONTENT = "bind pipeline call back $CONTENT_TEMPLATE" +
" in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_DELETE_CONTENT = "delete pipeline $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_DELETE_VERSION_CONTENT = "delete pipeline version $CONTENT_TEMPLATE " +
"in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_EXECUTE_CONTENT = "execute pipeline $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"

// 流水线模板
const val PIPELINE_TEMPLATE_CREATE_CONTENT = "create template $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_TEMPLATE_EDIT_COPY_CONTENT = "copy template $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_TEMPLATE_EDIT_SAVE_AS_CONTENT = "save as template $CONTENT_TEMPLATE " +
"in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_TEMPLATE_DELETE_CONTENT = "delete template $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_TEMPLATE_EDIT_SETTING_CONTENT = "update template setting $CONTENT_TEMPLATE " +
"in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val PIPELINE_TEMPLATE_EDIT_CONTENT = "update template $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"

// 证书
const val CERT_CREATE_CONTENT = "create cert $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CERT_VIEW_CONTENT = "get cert info $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CERT_EDIT_CONTENT = "update cert $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CERT_DELETE_CONTENT = "delete cert $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CERT_LIST_CONTENT = "list cert $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CERT_USE_CONTENT = "use cert $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"

// 凭据
const val CREDENTIAL_CREATE_CONTENT = "create credential $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CREDENTIAL_VIEW_CONTENT = "get credential info $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CREDENTIAL_EDIT_CONTENT = "update credential $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CREDENTIAL_EDIT_SETTING_CONTENT = "update credential setting $CONTENT_TEMPLATE " +
"in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CREDENTIAL_DELETE_CONTENT = "delete credential $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CREDENTIAL_LIST_CONTENT = "list credential $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CREDENTIAL_USE_CONTENT = "use credential $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"

// 云桌面
const val CGS_CREATE_CONTENT = "create workspace $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_LIST_CONTENT = "list workspace $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_VIEW_CONTENT = "get workspace $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_STOP_CONTENT = "stop workspace $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_START_CONTENT = "start workspace $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_RESTART_CONTENT = "restart workspace $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_ASSIGN_USER_CONTENT = "assign workspace $CONTENT_TEMPLATE " +
"to [{{$ASSIGNS_TEMPLATE}}] from $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_ASSIGN_PROJECT_CONTENT = "assign workspace $CONTENT_TEMPLATE to project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_EDIT_TYPE_CONTENT = "modify workspace type $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_REBUILD_SYSTEM_DISK_CONTENT = "rebuild workspace system disk $CONTENT_TEMPLATE " +
"in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_MAKE_IMAGE_CONTENT = "make workspace image $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_EXPAND_DISK_CONTENT = "expand workspace disk $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_DELETE_CONTENT = "delete workspace $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_SHARE_CONTENT = "share workspace $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CGS_EDIT_CONTENT = "edit workspace $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"

// 云桌面镜像
const val IMAGE_LIST_CONTENT = "list workspace image $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val IMAGE_DELETE_CONTENT = "delete workspace image $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val IMAGE_EDIT_CONTENT = "modify workspace image $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"

// 代理仓库
const val CODE_PROXY_CREATE_CONTENT = "create code proxy $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CODE_PROXY_LIST_CONTENT = "list code proxy $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
const val CODE_PROXY_DELETE_CONTENT = "delete code proxy $CONTENT_TEMPLATE in project $PROJECT_CODE_CONTENT_TEMPLATE"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.tencent.devops.common.audit

import com.tencent.bk.audit.AuditRequestProvider
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary

@Configuration
@ConditionalOnProperty(name = ["audit.enabled"], havingValue = "true", matchIfMissing = true)
class BkAuditConfiguration {
@Bean
@Primary
fun bkAuditRequestProvider(): AuditRequestProvider {
return BkAuditRequestProvider()
}

@Bean
fun bkAuditPostFilter(): BkAuditPostFilter {
return BkAuditPostFilter()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.tencent.devops.common.audit

import com.tencent.bk.audit.filter.AuditPostFilter
import com.tencent.bk.audit.model.AuditEvent

class BkAuditPostFilter : AuditPostFilter {
override fun map(auditEvent: AuditEvent): AuditEvent {
auditEvent.scopeType = "project"
return auditEvent
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.tencent.devops.common.audit

import com.tencent.bk.audit.AuditRequestProvider
import com.tencent.bk.audit.constants.AccessTypeEnum
import com.tencent.bk.audit.constants.UserIdentifyTypeEnum
import com.tencent.bk.audit.exception.AuditException
import com.tencent.bk.audit.model.AuditHttpRequest
import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID
import com.tencent.devops.common.api.constant.REQUEST_CHANNEL
import com.tencent.devops.common.api.constant.REQUEST_IP
import com.tencent.devops.common.api.enums.RequestChannelTypeEnum
import org.slf4j.LoggerFactory
import org.springframework.web.context.request.RequestContextHolder
import org.springframework.web.context.request.ServletRequestAttributes
import javax.servlet.http.HttpServletRequest

class BkAuditRequestProvider : AuditRequestProvider {
companion object {
private const val HEADER_USER_IDENTIFY_TENANT_ID = "X-User-Identify-Tenant-Id"
private const val HEADER_USER_IDENTIFY_TYPE = "X-User-Identify-Type"
private const val HEADER_REQUEST_ID = "X-DEVOPS-RID"
private val logger = LoggerFactory.getLogger(BkAuditRequestProvider::class.java)
}

override fun getRequest(): AuditHttpRequest {
val httpServletRequest: HttpServletRequest = getHttpServletRequest()
return AuditHttpRequest(httpServletRequest)
}

private fun getHttpServletRequest(): HttpServletRequest {
val requestAttributes = RequestContextHolder.getRequestAttributes()
if (requestAttributes == null) {
logger.error("Could not get RequestAttributes from RequestContext!")
throw AuditException("Parse http request error")
}
return (requestAttributes as ServletRequestAttributes).request
}

override fun getUsername(): String? {
val httpServletRequest = getHttpServletRequest()
return httpServletRequest.getHeader(AUTH_HEADER_USER_ID)
}

override fun getUserIdentifyType(): UserIdentifyTypeEnum? {
val httpServletRequest = getHttpServletRequest()
return UserIdentifyTypeEnum.valOf(
httpServletRequest.getHeader(HEADER_USER_IDENTIFY_TYPE)
)
}

override fun getUserIdentifyTenantId(): String? {
val httpServletRequest = getHttpServletRequest()
return httpServletRequest.getHeader(HEADER_USER_IDENTIFY_TENANT_ID)
}

override fun getAccessType(): AccessTypeEnum {
val httpServletRequest = getHttpServletRequest()
val requestChannel = (httpServletRequest.getAttribute(REQUEST_CHANNEL)
?: httpServletRequest.getHeader(REQUEST_CHANNEL))?.toString()
logger.debug("get request channel:$requestChannel")
return when (requestChannel) {
RequestChannelTypeEnum.USER.name,
RequestChannelTypeEnum.OP.name -> AccessTypeEnum.WEB
RequestChannelTypeEnum.API.name -> AccessTypeEnum.API
else -> AccessTypeEnum.OTHER
}
}

override fun getRequestId(): String? {
val httpServletRequest = getHttpServletRequest()
return httpServletRequest.getHeader(HEADER_REQUEST_ID)
}

override fun getClientIp(): String? {
val request = getHttpServletRequest()
val xff = request.getHeader(REQUEST_IP)
return if (xff == null) {
request.remoteAddr
} else {
if (xff.contains(",")) xff.split(",".toRegex()).toTypedArray()[0] else xff
}
}

override fun getUserAgent(): String? {
val request = getHttpServletRequest()
return request.getHeader("User-Agent")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.devops.common.audit.BkAuditConfiguration
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.tencent.devops.common.auth.api

object ActionId {
// 项目
const val PROJECT_MANAGE = "project_manage"

// 流水线
const val PIPELINE_CREATE = "pipeline_create"
const val PIPELINE_VIEW = "pipeline_view"
const val PIPELINE_EDIT = "pipeline_edit"
const val PIPELINE_DELETE = "pipeline_delete"
const val PIPELINE_EXECUTE = "pipeline_execute"
const val PIPELINE_LIST = "pipeline_list"
const val PIPELINE_SHARE = "pipeline_share"
const val PIPELINE_DOWNLOAD = "pipeline_download"

// 流水线模板
const val PIPELINE_TEMPLATE_CREATE = "pipeline_template_create"
const val PIPELINE_TEMPLATE_EDIT = "pipeline_template_edit"
const val PIPELINE_TEMPLATE_DELETE = "pipeline_template_delete"

// 凭据
const val CREDENTIAL_CREATE = "credential_create"
const val CREDENTIAL_VIEW = "credential_view"
const val CREDENTIAL_EDIT = "credential_edit"
const val CREDENTIAL_DELETE = "credential_delete"
const val CREDENTIAL_LIST = "credential_list"
const val CREDENTIAL_USE = "credential_use"

// 证书
const val CERT_CREATE = "cert_create"
const val CERT_VIEW = "cert_view"
const val CERT_EDIT = "cert_edit"
const val CERT_DELETE = "cert_delete"
const val CERT_LIST = "cert_list"
const val CERT_USE = "cert_use"

// 云桌面
const val CGS_CREATE = "cgs_create"
const val CGS_LIST = "cgs_list"
const val CGS_VIEW = "cgs_view"
const val CGS_STOP = "cgs_stop"
const val CGS_START = "cgs_start"
const val CGS_RESTART = "cgs_restart"
const val CGS_ASSIGN = "cgs_assign"
const val CGS_EDIT_TYPE = "cgs_edit-type"
const val CGS_REBUILD_SYSTEM_DISK = "cgs_rebuild-system-disk"
const val CGS_MAKE_IMAGE = "cgs_make-image"
const val CGS_EXPAND_DISK = "cgs_expand-disk"
const val CGS_DELETE = "cgs_delete"
const val CGS_SHARE = "cgs_share"
const val CGS_EDIT = "cgs_edit"

// 镜像
const val IMAGE_LIST = "image_list"
const val IMAGE_DELETE = "image_delete"
const val IMAGE_EDIT = "image_edit"

// 代理仓库
const val CODE_PROXY_CREATE = "code_proxy_create"
const val CODE_PROXY_LIST = "code_proxy_list"
const val CODE_PROXY_DELETE = "code_proxy_delete"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.tencent.devops.common.auth.api

object ResourceTypeId {
const val PROJECT = "project"
const val PIPELINE = "pipeline"
const val PIPELINE_TEMPLATE = "pipeline_template"
const val CREDENTIAL = "credential"
const val CERT = "cert"
const val CGS = "cgs"
const val IMAGE = "image"
const val CODE_PROXY = "code_proxy"
}
Loading

0 comments on commit 45dee17

Please sign in to comment.