From 60eac5ebf6c547bdcd7405ae3af7044d9053509d Mon Sep 17 00:00:00 2001 From: Hardy Date: Thu, 13 Feb 2025 16:17:17 +0800 Subject: [PATCH] chore: auto init agent ingest user (#120) * chore: auto init agent ingest user * docs: update release notes --------- Co-authored-by: hardy --- .../common/data/system_ingest_config.dat | 4 +- docs/content.en/docs/release-notes/_index.md | 12 +- docs/content.zh/docs/release-notes/_index.md | 1 + plugin/setup/setup.go | 123 ++++++++++++++---- 4 files changed, 109 insertions(+), 31 deletions(-) diff --git a/config/setup/common/data/system_ingest_config.dat b/config/setup/common/data/system_ingest_config.dat index f65c78e2..7506d088 100644 --- a/config/setup/common/data/system_ingest_config.dat +++ b/config/setup/common/data/system_ingest_config.dat @@ -52,8 +52,8 @@ pipeline: Content-Type: application/json body: $[[message]] basic_auth: - username: $[[SETUP_ES_USERNAME]] - password: $[[SETUP_ES_PASSWORD]] + username: $[[SETUP_AGENT_USERNAME]] + password: $[[SETUP_AGENT_PASSWORD]] # tls: #for mTLS connection with config servers # enabled: true # ca_file: /xxx/ca.crt diff --git a/docs/content.en/docs/release-notes/_index.md b/docs/content.en/docs/release-notes/_index.md index cff427e7..5c9c36c1 100644 --- a/docs/content.en/docs/release-notes/_index.md +++ b/docs/content.en/docs/release-notes/_index.md @@ -18,14 +18,16 @@ Information about release notes of INFINI Console is provided here. ### Improvements -- add Copy request to alerting chart -- add credential settings for agent in enrolling agent -- add collection mode to cluster editing +- Add Buckets Diff to alerting rule +- Automatically create Agent metrics for system clusters when using Easysearch to store metrics Write least-privileged user (#120) +- Add Copy request to alerting chart +- Add credential settings for agent in enrolling agent +- Add collection mode to cluster editing ## 1.28.1 (2025-01-24) -- add credential settings for agent in enrolling agent -- add collection mode to cluster editing +- Add credential settings for agent in enrolling agent +- Add collection mode to cluster editing ### Features diff --git a/docs/content.zh/docs/release-notes/_index.md b/docs/content.zh/docs/release-notes/_index.md index 3aa547c4..21efd2a5 100644 --- a/docs/content.zh/docs/release-notes/_index.md +++ b/docs/content.zh/docs/release-notes/_index.md @@ -20,6 +20,7 @@ title: "版本历史" - 告警图表新增复制请求 - 在注册 Agent 中新增 Agent 凭据设置 - 在集群编辑中新增采集模式 +- 当使用 Easysearch 存储指标时,自动为系统集群创建 Agent 指标写入最小权限用户 (#120) ## 1.28.1 (2025-01-24) diff --git a/plugin/setup/setup.go b/plugin/setup/setup.go index 2c4519dc..e8dd2a85 100644 --- a/plugin/setup/setup.go +++ b/plugin/setup/setup.go @@ -69,6 +69,8 @@ import ( "infini.sh/framework/plugins/replay" ) +const ingestUser = "infini_ingest" + type Module struct { api.Handler } @@ -492,30 +494,9 @@ func (module *Module) initialize(w http.ResponseWriter, r *http.Request, ps http if reuseOldCred { toSaveCfg.CredentialID = oldCfg.CredentialID } else { - cred := credential.Credential{ - Name: "INFINI_SYSTEM", - Type: credential.BasicAuth, - Tags: []string{"infini", "system"}, - Payload: map[string]interface{}{ - "basic_auth": map[string]interface{}{ - "username": request.Cluster.Username, - "password": request.Cluster.Password, - }, - }, - } - cred.ID = util.GetUUID() - err = cred.Encode() - if err != nil { - panic(err) - } - toSaveCfg.CredentialID = cred.ID - cfg.CredentialID = cred.ID - now := time.Now() - cred.Created = &now - err = orm.Save(nil, &cred) - if err != nil { - panic(err) - } + credId := createCred("INFINI_SYSTEM", request.Cluster.Username, request.Cluster.Password) + cfg.CredentialID = credId + toSaveCfg.CredentialID = credId toSaveCfg.BasicAuth = nil } } @@ -598,6 +579,7 @@ func (module *Module) initialize(w http.ResponseWriter, r *http.Request, ps http success = true } + func (module *Module) validateSecret(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { err, client, request := module.initTempClient(r) if err != nil { @@ -659,6 +641,34 @@ func validateCredentialSecret(ormHandler orm.ORM, credentialSecret string) (bool return exists, nil } +func createCred(name, username, password string) string { + cred := credential.Credential{ + Name: name, + Type: credential.BasicAuth, + Tags: []string{"infini", "system"}, + Payload: map[string]interface{}{ + "basic_auth": map[string]interface{}{ + "username": username, + "password": password, + }, + }, + } + cred.ID = util.GetUUID() + err := cred.Encode() + if err != nil { + panic(err) + } + + now := time.Now() + cred.Created = &now + cred.Updated = &now + err = orm.Save(nil, &cred) + if err != nil { + panic(err) + } + return cred.ID +} + func getYamlData(filename string) []byte { baseDir := path.Join(global.Env().GetConfigDir(), "setup") filePath := path.Join(baseDir, "common", "data", filename) @@ -775,6 +785,21 @@ func (module *Module) initializeTemplate(w http.ResponseWriter, r *http.Request, }, http.StatusOK) return } + + // Easysearch auto create ingest user + ingestPassword := util.GenerateRandomString(20) + if ver.Distribution == elastic.Easysearch { + err = keystore.SetValue("SYSTEM_CLUSTER_INGEST_PASSWORD", []byte(ingestPassword)) + if err != nil { + panic(err) + } + client := elastic.GetClient(GlobalSystemElasticsearchID) + err = initIngestUser(client, cfg1.IndexPrefix, ingestUser, ingestPassword) + if err != nil { + panic(err) + } + } + output := tpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { switch tag { case "SETUP_SYSTEM_INGEST_CONFIG": @@ -795,6 +820,18 @@ func (module *Module) initializeTemplate(w http.ResponseWriter, r *http.Request, return w.Write([]byte(request.Cluster.Username)) case "SETUP_ES_PASSWORD": return w.Write([]byte(request.Cluster.Password)) + case "SETUP_AGENT_USERNAME": + if ver.Distribution == elastic.Easysearch { + return w.Write([]byte(ingestUser)) + } else { + return w.Write([]byte(request.Cluster.Username)) + } + case "SETUP_AGENT_PASSWORD": + if ver.Distribution == elastic.Easysearch { + return w.Write([]byte(ingestPassword)) + } else { + return w.Write([]byte(request.Cluster.Password)) + } case "SETUP_SCHEME": return w.Write([]byte(strings.Split(request.Cluster.Endpoint, "://")[0])) case "SETUP_ENDPOINTS": @@ -867,3 +904,41 @@ func (module *Module) initializeTemplate(w http.ResponseWriter, r *http.Request, }, http.StatusOK) } + +func initIngestUser(client elastic.API, indexPrefix string, username, password string) error { + roleTpl := `{ + "cluster": [ + "cluster_monitor", + "cluster_composite_ops" + ], + "description": "Provide the minimum permissions for INFINI AGENT to write metrics and logs", + "indices": [{ + "names": [ + "%slogs*", "%smetrics*" + ], + "query": "", + "field_security": [], + "field_mask": [], + "privileges": [ + "create_index","index","manage_aliases","write" + ] + }] + }` + roleBody := fmt.Sprintf(roleTpl, indexPrefix, indexPrefix) + err := client.PutRole(ingestUser, []byte(roleBody)) + if err != nil { + return fmt.Errorf("failed to create ingest role: %w", err) + } + userTpl := `{ + "roles": [ + "%s" + ], + "password": "%s"}` + + userBody := fmt.Sprintf(userTpl, ingestUser, password) + err = client.PutUser(username, []byte(userBody)) + if err != nil { + return fmt.Errorf("failed to create ingest user: %w", err) + } + return nil +}