chore: auto init agent ingest user (#120)

* chore: auto init agent ingest user

* docs: update release notes

---------

Co-authored-by: hardy <luohf@infinilabs.com>
This commit is contained in:
Hardy 2025-02-13 16:17:17 +08:00 committed by GitHub
parent 2f94f14d79
commit 60eac5ebf6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 109 additions and 31 deletions

View File

@ -52,8 +52,8 @@ pipeline:
Content-Type: application/json Content-Type: application/json
body: $[[message]] body: $[[message]]
basic_auth: basic_auth:
username: $[[SETUP_ES_USERNAME]] username: $[[SETUP_AGENT_USERNAME]]
password: $[[SETUP_ES_PASSWORD]] password: $[[SETUP_AGENT_PASSWORD]]
# tls: #for mTLS connection with config servers # tls: #for mTLS connection with config servers
# enabled: true # enabled: true
# ca_file: /xxx/ca.crt # ca_file: /xxx/ca.crt

View File

@ -18,14 +18,16 @@ Information about release notes of INFINI Console is provided here.
### Improvements ### Improvements
- add Copy request to alerting chart - Add Buckets Diff to alerting rule
- add credential settings for agent in enrolling agent - Automatically create Agent metrics for system clusters when using Easysearch to store metrics Write least-privileged user (#120)
- add collection mode to cluster editing - 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) ## 1.28.1 (2025-01-24)
- add credential settings for agent in enrolling agent - Add credential settings for agent in enrolling agent
- add collection mode to cluster editing - Add collection mode to cluster editing
### Features ### Features

View File

@ -20,6 +20,7 @@ title: "版本历史"
- 告警图表新增复制请求 - 告警图表新增复制请求
- 在注册 Agent 中新增 Agent 凭据设置 - 在注册 Agent 中新增 Agent 凭据设置
- 在集群编辑中新增采集模式 - 在集群编辑中新增采集模式
- 当使用 Easysearch 存储指标时,自动为系统集群创建 Agent 指标写入最小权限用户 (#120)
## 1.28.1 (2025-01-24) ## 1.28.1 (2025-01-24)

View File

@ -69,6 +69,8 @@ import (
"infini.sh/framework/plugins/replay" "infini.sh/framework/plugins/replay"
) )
const ingestUser = "infini_ingest"
type Module struct { type Module struct {
api.Handler api.Handler
} }
@ -492,30 +494,9 @@ func (module *Module) initialize(w http.ResponseWriter, r *http.Request, ps http
if reuseOldCred { if reuseOldCred {
toSaveCfg.CredentialID = oldCfg.CredentialID toSaveCfg.CredentialID = oldCfg.CredentialID
} else { } else {
cred := credential.Credential{ credId := createCred("INFINI_SYSTEM", request.Cluster.Username, request.Cluster.Password)
Name: "INFINI_SYSTEM", cfg.CredentialID = credId
Type: credential.BasicAuth, toSaveCfg.CredentialID = credId
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)
}
toSaveCfg.BasicAuth = nil toSaveCfg.BasicAuth = nil
} }
} }
@ -598,6 +579,7 @@ func (module *Module) initialize(w http.ResponseWriter, r *http.Request, ps http
success = true success = true
} }
func (module *Module) validateSecret(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (module *Module) validateSecret(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
err, client, request := module.initTempClient(r) err, client, request := module.initTempClient(r)
if err != nil { if err != nil {
@ -659,6 +641,34 @@ func validateCredentialSecret(ormHandler orm.ORM, credentialSecret string) (bool
return exists, nil 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 { func getYamlData(filename string) []byte {
baseDir := path.Join(global.Env().GetConfigDir(), "setup") baseDir := path.Join(global.Env().GetConfigDir(), "setup")
filePath := path.Join(baseDir, "common", "data", filename) filePath := path.Join(baseDir, "common", "data", filename)
@ -775,6 +785,21 @@ func (module *Module) initializeTemplate(w http.ResponseWriter, r *http.Request,
}, http.StatusOK) }, http.StatusOK)
return 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) { output := tpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) {
switch tag { switch tag {
case "SETUP_SYSTEM_INGEST_CONFIG": 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)) return w.Write([]byte(request.Cluster.Username))
case "SETUP_ES_PASSWORD": case "SETUP_ES_PASSWORD":
return w.Write([]byte(request.Cluster.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": case "SETUP_SCHEME":
return w.Write([]byte(strings.Split(request.Cluster.Endpoint, "://")[0])) return w.Write([]byte(strings.Split(request.Cluster.Endpoint, "://")[0]))
case "SETUP_ENDPOINTS": case "SETUP_ENDPOINTS":
@ -867,3 +904,41 @@ func (module *Module) initializeTemplate(w http.ResponseWriter, r *http.Request,
}, http.StatusOK) }, 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
}