Automating Secure Skill Insertions into Databases Using Jenkins Pipelines

Automating Secure Skill Insertions into Databases Using Jenkins Pipelines

 

Managing frequent database insertions without giving developers direct database access is crucial for maintaining security, data integrity, and operational efficiency. A Jenkins pipeline is a perfect solution for this. This blog explores how to set up a Jenkins pipeline to safely run regular database insertions, such as adding new skill names, with complete auditing and access control, without exposing database credentials or direct access to developers.

Use Case

Let’s say your application needs to frequently insert a new skill name into the skill table. Instead of letting developers run SQL queries manually (which risks data inconsistency and security), we automate this via Jenkins.

Key Challenges Without Automation:

  • Developers require DB credentials
  • Manual queries are error-prone
  • Difficult to maintain audit logs

Pipeline Automation Benefits:

  • Centralized and secure credential management
  • Automatic auditing
  • Easy-to-use interface for developers

Jenkins Pipeline Overview

Pipeline at a glance
 

Below is a simplified yet powerful Jenkins pipeline for this use case:

pipeline {

    agent none




    parameters {

        choice(name: 'AGENT_LABEL', choices: ['Agent1_Dev', 'Agent2_Prod'], description: 'Select Agent Label')

        text(name: 'SKILL_NAME', defaultValue: 'Scrum Master', description: 'Enter the skill name to be inserted')

    }




    stages {

        stage('Insert Skill into DB') {

            agent {

                label "${params.AGENT_LABEL}"

            }

            steps {

                script {

                    def props = readFile('/mnt/application.properties').readLines()

                    def propMap = [:]

                    props.each { line ->

                        if (line.contains("=")) {

                            def (key, value) = line.split('=', 2)

                            propMap[key.trim()] = value.trim()

                        }

                    }




                    def jdbcUrl = propMap['spring.datasource.url']

                    def dbUser = propMap['spring.datasource.username']

                    def dbPassword = propMap['spring.datasource.password']

                    def (dbHost, dbName) = parseJdbcUrl(jdbcUrl)




                    def skillName = params.SKILL_NAME.trim()

                    def userId = currentBuild.rawBuild.getCause(hudson.model.Cause$UserIdCause)?.userId

                    def triggeredBy = userId?.split('@')[0]?.split('\\.')?.collect { it.capitalize() }?.join(' ') ?: 'system'

                    def now = new Date().format("yyyy-MM-dd HH:mm:ss")

                    def auditFile = "/mnt/skill_insert_audit_log.csv"




                    writeFile file: '.my.cnf', text: """

                        [client]

                        user=${dbUser}

                        password=${dbPassword}

                        host=${dbHost}

                    """




                    sh 'chmod 600 .my.cnf'




                    try {

                        def query = """

                            INSERT INTO skill(

                                active, created_on, created_by, skill_name

                            ) VALUES (

                                true, now(), '${triggeredBy}', '${skillName}'

                            );

                        """




                        def exitCode = sh(

                            script: """mysql --defaults-file=.my.cnf ${dbName} -e \"${query}\" 2> mysql_error.log""",

                            returnStatus: true

                        )




                        def errorOutput = readFile('mysql_error.log').trim()




                        if (exitCode != 0) {

                            if (errorOutput.contains("Duplicate entry")) {

                                echo "Skill '${skillName}' already exists. Skipping insert."

                            } else {

                                error "MySQL Error: ${errorOutput}"

                            }

                        } else {

                            echo "Skill '${skillName}' inserted successfully by ${triggeredBy}."

                            def csvLine = "${now}, ${env.BUILD_NUMBER}, ${params.AGENT_LABEL}, ${skillName}, ${triggeredBy}\n"

                            writeFile file: 'temp_audit_log.csv', text: csvLine

                            sh "cat temp_audit_log.csv >> ${auditFile}"

                            sh "rm -f temp_audit_log.csv"

                        }

                    } finally {

                        sh 'rm -f .my.cnf'

                    }

                }

            }

        }

    }

}




@NonCPS

def parseJdbcUrl(jdbcUrl) {

    def matcher = jdbcUrl =~ /jdbc:mysql:\/\/(.*?):\d+\/(.*)/

    return [matcher[0][1], matcher[0][2]]

}

Advantages Over Direct DB Access

Feature Jenkins Pipeline Direct Developer DB Access
Security Credentials hidden using .properties file Credentials exposed
Audit Logging Maintains a CSV log of all insertions Manual effort needed
Controlled Access Only whitelisted agents can run queries All developers need access
Ease of Use Devs just input skill name Devs write and run SQL manually
Error Handling Built-in duplicate check and logs Error-prone and inconsistent

How It Works

Key Pipeline Actions:

  • ✅ Reads DB credentials from /mnt/application.properties
  • ✅ Parses JDBC URL to get DB host and name
  • ✅ Inserts skill with metadata (creator, timestamp)
  • ✅ Logs to /mnt/skill_insert_audit_log.csv

Jenkins UI to trigger skill insert job


Final Thoughts

This pipeline is a practical example of how to offload frequent DB operations from developers and run them safely in a controlled environment. It is extensible to any kind of query-based automation where auditability and security are required.

Key Takeaways:

  • Improve database security by eliminating direct access
  • Enable developers to trigger safe queries with one click
  • Maintain a robust and searchable audit trail

Such Jenkins pipelines simplify operations, improve compliance, and protect your database integrity without adding burden to developers or database administrators.

Leave a Reply